MongoDB a Postgres
🚨 Esta publicación del blog es una fusión de mi MongoDB a Postgres (2024-03-06) y Sequelize vs. Prisma (2023-05-25). Los blogs originales han sido eliminados, y este blog ha tomado su lugar ya que ambos contenían esencialmente el mismo contenido/información. La migración comenzó en principios de marzo de 2023, el cambio ocurrió en mediados de noviembre de 2023, y todas las instancias del antiguo sistema MongoDB se apagaron completamente en principios de enero de 2024.
Introducción
Durante mi tiempo en eBay, enfrenté lo que se convirtió en el problema técnicamente más desafiante de mi carrera: migrar el Sistema de Gestión de Almacenamiento (STMS) de MongoDB a Postgres. No se trató solo de un simple intercambio de bases de datos; fue una transformación arquitectónica completa de un sistema crítico que ingiere más de 1,5 millones de métricas por minuto en los centros de datos de eBay, con el requisito de cero tiempo de inactividad y manteniendo casi toda la funcionalidad existente.
¿Qué es STMS?
El Sistema de Gestión de Almacenamiento (STMS) sirve como una herramienta interna crítica para el equipo de Infraestructura de Servicio y Almacenamiento (SSI) de eBay. Monitorea y gestiona dispositivos en los centros de datos de eBay, permitiendo a los ingenieros:
- Monitorear métricas de docenas de matrices, switches, hosts, grupos de discos y clústeres
- Manejar alertas para switches y matrices
- Completar tareas avanzadas como asignaciones de hosts
- Acceder a datos en tiempo real para otros servicios internos de eBay
STMS abarca más de 70 matrices, 60 switches, 1100 hosts, 900 grupos de discos y 200 clústeres en 3 de los centros de datos de eBay. Dado su papel vital en la infraestructura de eBay, cualquier tiempo de inactividad o pérdida de funcionalidad impactaría directamente los servicios centrales y las operaciones comerciales de la compañía.
El Desafío
Por Qué la Migración Fue Necesaria
La decisión de migrar de MongoDB a Postgres no se tomó a la ligera. Si bien MongoDB había servido bien a STMS inicialmente, la creciente complejidad de nuestras relaciones de datos y la necesidad de capacidades de consulta más sofisticadas hicieron que Postgres fuera una mejor solución a largo plazo para nuestro caso de uso.
Qué Hizo Este Problema Difícil
La complejidad de esta migración surgió de varios desafíos fundamentales:
1. Diferencias Fundamentales de Bases de Datos
MongoDB y Postgres son bases de datos fundamentalmente diferentes. MongoDB es una base de datos basada en documentos (NoSQL), lo que significa que los datos se almacenan como JSON en colecciones, como documentos en un archivo. Postgres es una base de datos relacional (SQL), lo que significa que los datos se almacenan como filas en tablas, como en una hoja de cálculo.
2. Arquitectura del Código
Todo el backend de STMS se construyó para procesar y gestionar datos como JSONs, usando paquetes exclusivamente compatibles con MongoDB para operaciones de base de datos. Esto implicó no solo cambiar la base de datos, sino reestructurar cómo toda nuestra aplicación manejaba los datos.
3. Requisito de Cero Tiempo de Inactividad
Debido a lo vital que es STMS como herramienta interna, no podía haber tiempo de inactividad durante la migración. El sistema debía seguir sirviendo más de 1,5 millones de métricas por minuto durante todo el proceso.
4. Cronograma Ajustado y Experiencia Limitada
La migración debía completarse en unos pocos meses, sin un plan de ejecución claro inicialmente. Ni yo ni mis compañeros teníamos experiencia migrando una base de código heredada grande de NoSQL a bases de datos SQL, y yo tenía experiencia limitada previa con Postgres.
5. Escala y Complejidad
La migración involucró convertir 36 colecciones de MongoDB en 74 tablas de Postgres, requiriendo una consideración cuidadosa de relaciones, indexación y optimización de consultas.
Elegir el ORM Correcto: Sequelize vs Prisma
Una de las primeras decisiones importantes fue seleccionar una herramienta ORM (Mapeo Objeto-Relacional). Dado que nuestra base de código ya estaba diseñada para usar Mongoose con MongoDB, usar un ORM proporcionaría la ruta de transición más fluida.
Análisis de Requisitos
Después de un análisis cuidadoso de las necesidades del proyecto, establecí criterios esenciales para cualquier solución ORM:
- Debe ser un paquete de JavaScript (la mayor parte de nuestro código estaba escrito en JavaScript)
- Debe soportar Postgres y la mayoría de sus características
- El rendimiento debe estar al menos a la par o ser mejor que Mongoose
- Debe ser de código abierto y mantenido
Los Candidatos
Tras una investigación exhaustiva, reduje la lista a dos contendientes principales: Sequelize y Prisma. Creé entornos de prueba integrales usando Docker para Postgres y convertí nuestro conjunto de datos más grande y complejo de estructura de documento a estructura de tabla.
Metodología de Pruebas
Para cada ORM, medí el rendimiento en operaciones críticas:
- Tiempo para crear una entrada
- Tiempo para actualizar una entrada
- Tiempo para actualizar entradas anidadas (relaciones y pares clave‑valor JSON)
- Tiempo para eliminar una entrada
- Tiempo para consultar/obtener una entrada
La Decisión: Sequelize
Alrededor del 15 de mayo de 2023, decidí que Sequelize era el ORM más adecuado para nuestro caso de uso. Aquí está el porqué:
Ventajas de Sequelize:
- Realmente de código abierto y no mantenido por una startup financiada
- Soporta la mayoría de las características de Postgres
- Mejor rendimiento, especialmente en comparación con Prisma
- Ecosistema maduro con más de 10 años de desarrollo
- Representación flexible de modelo/esquema usando clases de JavaScript
- Soporte para joins complejos y opciones de filtrado incluyendo Regex
Resultados de Rendimiento:
En mis pruebas, Sequelize superó significativamente a Prisma. Para nuestras entradas de gran conjunto de datos:
- Sequelize: ~2,26 segundos por entrada
- Prisma: ~11,21 segundos por entrada
Prisma fue aproximadamente 5 × más lento que Sequelize para nuestro caso de uso. Además, eliminar una entrada de nuestro conjunto de datos más grande tomó a Prisma casi 4 minutos, lo cual era inaceptable para nuestros requisitos.
Desafíos de Sequelize:
- Representaciones de modelo más complejas y infladas (564 líneas vs 262 líneas para Mongoose)
- Sintaxis confusa en ciertos casos
- Complejidad en la migración de bases de datos
- Documentación menos completa comparada con Prisma
Comparación de Pros y Contras de Sequelize y Prisma
Para ofrecer una visión más completa de por qué elegí Sequelize, quiero compartir los pros y contras detallados que compilé para ambos ORMs durante mi evaluación. También analicé cómo se comparaban en términos de representación de esquema y soporte comunitario al 15 de mayo de 2023. Esta inmersión más profunda consolidó mi elección, y espero que pueda ser útil para cualquier otra persona que enfrente una decisión similar.
Pros de Sequelize:
- Tiene una función
sync()
que crea y maneja tablas automáticamente, ahorrando mucho esfuerzo manual. - Puede manejar joins complejos para datos anidados, lo cual era crítico para la estructura de STMS.
- Soporta una amplia gama de opciones de filtrado, incluyendo Regex, brindando flexibilidad en las consultas.
- La representación de modelo/esquema se realiza en JavaScript puro usando clases, lo que permite una alta personalización para necesidades específicas.
- Maneja conexiones a bases de datos sin problemas, incluyendo soporte para múltiples conexiones de lectura.
- Soporta consultas SQL crudas para cuando necesitas profundizar bajo el capó.
- Estadísticas de la comunidad al 15 de mayo de 2023: En NPM, actualizado hace 14 días con 1.505.835 descargas semanales; en GitHub, actualizado ayer con 4,2k forks y 27,9k estrellas. Ha sido de código abierto con licencia MIT por más de 10 años, así que confío en que seguirá así.
Contras de Sequelize:
- La representación de modelo/esquema puede volverse muy compleja e inflada. Por ejemplo, mientras la representación en Mongoose de nuestro gran conjunto de datos tenía alrededor de 262 líneas (incluyendo espacios), la misma dataset en Sequelize se infló a 564 líneas.
- La sintaxis puede ser confusa y complicada en ciertos escenarios, lo que me ralentizó en ocasiones.
- Migrar o editar la base de datos es una molestia. Incluso con
sequelize-cli
generando scripts de migración, sigue siendo engorroso, aunque he notado que este es un punto de dolor común en la mayoría de los ORMs. - La documentación no es excelente, aunque está mejorando. Afortunadamente, herramientas como ChatGPT tienen un buen dominio de Sequelize debido a su larga historia, lo que ayudó a llenar los vacíos.
- No es tan sensible a tipos como Prisma, lo que podría generar problemas en algunos proyectos.
- Soporte limitado para TypeScript, aunque esto no fue una preocupación para STMS, podría ser un factor decisivo para otros.
Pros de Prisma:
- Usa su propio lenguaje de esquema, haciendo la creación de modelos más limpia y concisa. En comparación, mientras Mongoose tomó 262 líneas para nuestro gran conjunto de datos, Prisma lo gestionó en solo 221 líneas.
- Viene con una herramienta CLI que simplifica la creación y migración de bases de datos, siendo la mejor que he visto en un ORM hasta ahora, aunque no es perfecta.
- Soporta consultas SQL crudas, ofreciendo flexibilidad cuando es necesario.
- La sintaxis del código es limpia y más simple de entender comparada con Sequelize, facilitando el aprendizaje.
- Genera automáticamente constructores de consultas para Node.js y TypeScript a través de su cliente, lo cual es un detalle agradable.
- Tiene una documentación excelente y limpia. ChatGPT no está tan actualizado en Prisma, pero la documentación oficial a menudo compensa eso.
- Estadísticas de la comunidad al 15 de mayo de 2023: En NPM, actualizado hace 6 días con 1.344.705 descargas semanales; en GitHub, actualizado hace 3 horas con 1,1k forks y 31,3k estrellas.
Contras de Prisma:
- No soporta filtrado Regex para Postgres, aunque ofrece alternativas como “contains”, “includes” y “startsWith”.
- El rendimiento fue un problema importante en mis pruebas. Crear entradas para nuestro gran conjunto de datos tomó a Prisma alrededor de 11,21 segundos por entrada comparado con los 2,26 segundos de Sequelize, aproximadamente 5 × más lento.
- Eliminar una sola entrada del gran conjunto de datos tomó casi 4 minutos, lo que fue un factor decisivo para nuestras necesidades.
- Incluso con una comparación justa en un conjunto de datos complejo de relaciones de tres niveles, Sequelize fue significativamente más rápido en eliminaciones.
- Prisma está respaldado por una startup con 56,5 millones de dólares en financiación. Aunque su código principal de ORM es de código abierto bajo Apache‑2.0, me preocupa que puedan cambiar la licencia en el futuro, similar a lo ocurrido con MongoDB.
Estas comparaciones detalladas dejaron claro que Sequelize se alineaba mejor con las necesidades de STMS, especialmente en rendimiento y fiabilidad a largo plazo. Pero pensé que desglosarlo de esta manera podría ayudar a otros que enfrentan la misma elección para sus proyectos.
El Proceso de Migración
Transformación de la Estructura de Datos
Convertir la estructura de documentos de MongoDB a la estructura relacional de Postgres requirió una planificación cuidadosa. Tuve que:
- Analizar Relaciones: Identificar cómo los documentos de MongoDB se relacionan entre sí y diseñar relaciones de clave foránea apropiadas
- Normalizar Datos: Descomponer documentos anidados en tablas separadas donde sea apropiado
- Preservar Funciones JSON: Utilizar columnas JSONB para datos verdaderamente no estructurados que necesitaban permanecer flexibles
- Diseñar Índices: Crear índices apropiados para el rendimiento de consultas
Soluciones Personalizadas
La migración requirió desarrollar varias soluciones personalizadas:
1. Scripts de Migración de Datos Creé scripts exhaustivos para:
- Extraer datos de colecciones de MongoDB
- Transformar estructuras de documentos a formato relacional
- Importar datos a tablas de Postgres con relaciones adecuadas
2. Capa de Compatibilidad API Para mantener cero tiempo de inactividad, construí una capa de compatibilidad que podía:
- Enrutar solicitudes a MongoDB o Postgres según el estado de la migración
- Garantizar la consistencia de datos durante el período de transición
- Proporcionar mecanismos de respaldo
3. Middleware Personalizado Desarrollé middleware para manejar las diferencias en cómo MongoDB y Postgres gestionan ciertas operaciones, asegurando que los puntos finales de API existentes continuaran funcionando sin modificaciones.
Superando Desafíos Técnicos
Manejo de Relaciones Complejas
Uno de los mayores desafíos fue convertir los documentos incrustados de MongoDB a relaciones en Postgres. Por ejemplo, un solo documento de MongoDB podría contener:
- Propiedades básicas
- Objetos anidados que representan entidades relacionadas
- Arreglos de documentos incrustados
Esto debía descomponerse cuidadosamente en:
- Tablas principales para entidades principales
- Tablas de unión para relaciones muchos a muchos
- Relaciones de clave foránea para asociaciones uno a muchos
Optimización de Consultas
Los patrones de consulta de MongoDB no se traducen directamente a SQL. Tuve que:
- Reescribir pipelines de agregación complejos como uniones SQL
- Optimizar índices para los nuevos patrones de consulta
- Asegurar que el rendimiento de las consultas cumpliera o superara el rendimiento de MongoDB
Integridad de Datos
Garantizar la integridad de los datos durante la migración requería:
- Scripts de validación exhaustivos
- Procedimientos de reversión
- Sincronización de datos en tiempo real durante los períodos de transición
Resultados e Impacto
La migración de STMS de MongoDB a Postgres se completó con éxito sin tiempo de inactividad, manteniendo casi todas las funciones y la funcionalidad. Los resultados superaron las expectativas:
Mejoras de Rendimiento:
- El rendimiento de las consultas mejoró para consultas relacionales complejas
- Mejor consistencia e integridad de los datos
- Utilización de almacenamiento más eficiente
Beneficios Operacionales:
- Capacidades mejoradas de monitoreo y depuración
- Mejor integración con las herramientas basadas en SQL existentes de eBay
- Procedimientos de respaldo y recuperación mejorados
Impacto en el Equipo:
- Conocimiento del equipo mejorado sobre bases de datos relacionales
- Patrones establecidos para futuras migraciones de bases de datos
- Creación de herramientas y procesos reutilizables
Habilidades Técnicas Adquiridas
Este proyecto amplió significativamente mi experiencia técnica:
Tecnologías de Bases de Datos:
- Comprensión profunda de las características y optimización de Postgres
- Optimización de consultas SQL y ajuste de rendimiento
- Patrones de diseño de bases de datos y normalización
- Configuraciones de bases de datos primarias-standby
Herramientas de Desarrollo:
- ORM Sequelize y construcción de consultas
- Estrategias de migración de bases de datos
- Metodologías de pruebas de rendimiento
- Validación de datos y verificación de integridad
Patrones de Arquitectura:
- Estrategias de migración sin tiempo de inactividad
- Capas de compatibilidad API
- Patrones de abstracción de bases de datos
- Sistemas de monitoreo y alertas
Crecimiento Personal y Profesional
Este proyecto de migración fue transformador para mi desarrollo profesional. Me impulsó a territorio desconocido, requiriendo:
Habilidades de Liderazgo:
- Liderar un proyecto técnico complejo sin experiencia previa
- Tomar decisiones arquitectónicas críticas bajo presión
- Coordinar con múltiples equipos y partes interesadas
Habilidades de Resolución de Problemas:
- Descomponer problemas complejos en componentes manejables
- Desarrollar soluciones creativas a desafíos sin precedentes
- Equilibrar múltiples requisitos y limitaciones competidores
Comunicación y Trabajo en Equipo:
- Explicar conceptos técnicos a partes interesadas no técnicas
- Documentar procesos y decisiones para referencia futura
- Mentorizar a los miembros del equipo en nuevas tecnologías y patrones
Lecciones Aprendidas
Lecciones Técnicas
- La Selección de Base de Datos Importa: La elección entre NoSQL y SQL debe basarse en casos de uso específicos y requisitos a largo plazo
- Las Pruebas de Rendimiento son Críticas: Las ventajas teóricas no siempre se traducen en mejoras de rendimiento en el mundo real
- Planificación de la Migración: La planificación y pruebas exhaustivas son esenciales para migraciones complejas
- Inversión en Herramientas: Construir herramientas adecuadas desde el principio ahorra tiempo significativo y reduce errores
Lecciones de Gestión de Proyectos
- Comunicación con los Interesados: Actualizaciones regulares y comunicación clara evitan malentendidos
- Gestión de Riesgos: Contar con planes de contingencia y procedimientos de reversión es esencial
- Gestión de Cronogramas: Tiempo de reserva para desafíos inesperados y curvas de aprendizaje
- Documentación: Una documentación exhaustiva permite la transferencia de conocimiento y el mantenimiento futuro
Conclusión
La migración de STMS de MongoDB a Postgres se presenta como el problema técnico más desafiante y gratificante que he resuelto en mi carrera. Requirió no solo experiencia técnica, sino también liderazgo, planificación y adaptabilidad. El éxito del proyecto demostró que con una planificación adecuada, pruebas exhaustivas y compromiso con la excelencia, incluso los desafíos técnicos más complejos pueden superarse.
Esta experiencia cambió fundamentalmente mi enfoque de la ingeniería de software, enfatizando la importancia de:
- Entender el contexto completo y los requisitos antes de tomar decisiones técnicas
- Invertir tiempo en herramientas y pruebas adecuadas
- Mantener una comunicación clara a lo largo de proyectos complejos
- Estar dispuesto a aprender nuevas tecnologías y enfoques cuando sea necesario
El éxito de la migración no solo mejoró las capacidades de STMS, sino que también estableció patrones y procesos que continúan beneficiando los proyectos de infraestructura de eBay. Reforzó mi convicción de que abrazar desafíos desconocidos y superarlos es clave tanto para el desarrollo personal como profesional.
Al mirar atrás, este proyecto representa un punto de inflexión en mi carrera, transformándome de un desarrollador que implementa soluciones a un ingeniero que puede diseñar y liderar iniciativas técnicas complejas. La confianza y las habilidades adquiridas con esta experiencia continúan guiando mi enfoque hacia nuevos desafíos y oportunidades en la ingeniería de software.