MongoDB a Postgres

NOTA: Esta publicación del blog es una fusión de mi MongoDB a Postgres (2024-03-06) y Sequelize vs. Prisma (2023-05-25). Las entradas originales del blog han sido eliminadas, y este blog ha ocupado su lugar, ya que ambas contenían esencialmente el mismo contenido/información. La migración comenzó a principios de marzo de 2023, el cambio ocurrió a mediados de noviembre de 2023, y todas las instancias del antiguo sistema MongoDB se cerraron por completo a principios de enero de 2024.

Introducción

Durante mi tiempo en eBay, me enfrenté a lo que se convirtió en el problema más desafiante técnicamente de mi carrera: migrar el Storage Management System (STMS) de MongoDB a Postgres. Esto no fue solo un simple cambio de base 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 Storage Management System (STMS) sirve como una herramienta interna crítica para el equipo de Service & Storage Infrastructure (SSI) de eBay. Supervisa y administra dispositivos en los centros de datos de eBay, permitiendo a los ingenieros:

  • Supervisar métricas de docenas de matrices, switches, hosts, grupos de discos y clústeres
  • Gestionar el alertado para switches y matrices
  • Completar tareas avanzadas como asignaciones de hosts
  • Acceder a datos en tiempo real para otros servicios internos de eBay

STMS da cuenta de 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 afectaría directamente los servicios principales y las operaciones comerciales de la empresa.

El desafío

Por qué la migración era necesaria

La decisión de migrar de MongoDB a Postgres no se tomó a la ligera. Aunque MongoDB había servido bien a STMS al principio, la creciente complejidad de nuestras relaciones de datos y la necesidad de capacidades de consulta más sofisticadas hicieron de Postgres una mejor solución a largo plazo para nuestro caso de uso.

Qué hizo difícil este problema

La complejidad de esta migración surgió de varios desafíos fundamentales:

1. Diferencias fundamentales entre 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 archivador. 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 de la base de código Todo el backend de STMS estaba construido para procesar y administrar datos como JSON, usando paquetes exclusivamente compatibles con MongoDB para las operaciones de base de datos. Esto significaba 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 tenía que seguir sirviendo 1,5+ millones de métricas por minuto durante todo el proceso.

4. Cronograma ajustado y experiencia limitada La migración tenía que completarse en pocos meses, sin un plan de ejecución claro al principio. Ni yo ni mis compañeros teníamos experiencia migrando una base de código heredada grande de bases de datos NoSQL a SQL, y yo tenía experiencia previa limitada con Postgres.

5. Escala y complejidad La migración implicó convertir 36 colecciones de MongoDB en 74 tablas de Postgres, lo que requirió una consideración cuidadosa de las relaciones, la indexación y la optimización de consultas.

Elegir el ORM adecuado: 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 para MongoDB, usar un ORM proporcionaría la ruta de transición más fluida.

Análisis de requisitos

Tras 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 funciones
  • El rendimiento debe ser al menos igual o mejor que el de Mongoose
  • Debe ser de código abierto y mantenerse activamente

Los candidatos

Tras una extensa investigación, reduje la selección a dos contendientes principales: Sequelize y Prisma. Creé entornos de prueba completos usando Docker para Postgres y convertí nuestro conjunto de datos más grande y complejo de estructura documental a estructura tabular.

Metodología de prueba

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 mejor ORM para nuestro caso de uso. He aquí por qué:

Ventajas de Sequelize:

  • Verdaderamente de código abierto y no mantenido por una startup financiada
  • Soportaba la mayoría de las funciones 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 modelos/esquemas usando clases de JavaScript
  • Soporte para uniones complejas y opciones de filtrado, incluido Regex

Resultados de rendimiento:

En mis pruebas, Sequelize superó significativamente a Prisma. Para las entradas de nuestro gran conjunto de datos:

  • Sequelize: ~2,26 segundos por entrada
  • Prisma: ~11,21 segundos por entrada

Prisma era aproximadamente 5 veces 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 modelos más complejas y voluminosas (564 líneas frente a 262 líneas para Mongoose)
  • Sintaxis confusa en ciertos casos
  • Complejidad en la migración de la base de datos
  • Documentación menos completa en comparación con Prisma

Comparación de pros y contras de Sequelize y Prisma

Para dar una imagen más completa de por qué elegí Sequelize, quiero compartir los pros y contras detallados que recopilé para ambos ORM durante mi evaluación. También analicé cómo se comparaban en términos de representación de esquemas y apoyo de la comunidad a fecha del 15 de mayo de 2023. Esta exploración más profunda ayudó a consolidar mi elección, y espero que pueda ser útil para cualquiera que se enfrente a una decisión similar.

Pros de Sequelize:

  • Tiene una función sync() que crea y gestiona automáticamente tablas por ti, ahorrando mucho esfuerzo manual.
  • Puede manejar uniones complejas para datos anidados, lo que era crítico para la estructura de STMS.
  • Soporta una amplia gama de opciones de filtrado, incluido Regex, lo que da flexibilidad en las consultas.
  • La representación del modelo/esquema se realiza en JavaScript puro usando clases, que son altamente personalizables para adaptarse a necesidades específicas.
  • Gestiona las conexiones a la base de datos sin problemas, incluido el soporte para múltiples conexiones de lectura.
  • Soporta consultas SQL sin procesar cuando necesitas mirar bajo el capó.
  • Estadísticas de la comunidad a fecha del 15 de mayo de 2023: En NPM, última actualización hace 14 días con 1,505,835 descargas semanales; en GitHub, última actualización ayer con 4.2k bifurcaciones y 27.9k estrellas. Ha sido de código abierto con una licencia MIT durante más de 10 años, así que confío en que seguirá siendo así.

Contras de Sequelize:

  • La representación del modelo/esquema puede volverse muy compleja y voluminosa. Por ejemplo, mientras que la representación de Mongoose de nuestro gran conjunto de datos tenía unas 262 líneas (incluidos los espacios), el mismo conjunto de datos en Sequelize se disparó a 564 líneas.
  • La sintaxis puede ser confusa y complicada en ciertos escenarios, lo que a veces me ralentizaba.
  • 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 débil común en la mayoría de los ORM.
  • La documentación no es muy buena, aunque está mejorando. Por suerte, herramientas como ChatGPT tienen un buen dominio de Sequelize debido a su larga historia, lo que ayudó a cubrir las lagunas.
  • No es tan sensible al tipado como Prisma, lo que podría causar problemas en algunos proyectos.
  • Soporte limitado para TypeScript, aunque esto no era una preocupación para STMS, podría ser un factor decisivo para otros.

Pros de Prisma:

  • Usa su propio lenguaje de esquemas, lo que hace que la creación de modelos sea más limpia y concisa. A modo de comparación, mientras que Mongoose necesitó 262 líneas para nuestro gran conjunto de datos, Prisma lo logró en solo 221 líneas.
  • Viene con una herramienta CLI que simplifica la creación y migración de bases de datos, que es la mejor que he visto en un ORM hasta ahora, aunque no sea perfecta.
  • Soporta consultas SQL sin procesar, ofreciendo flexibilidad cuando se necesita.
  • La sintaxis del código es limpia y más sencilla de entender en comparación con Sequelize, lo que facilita su aprendizaje.
  • Genera automáticamente constructores de consultas para Node.js y TypeScript mediante su cliente, lo cual es un buen detalle.
  • Tiene una documentación excelente y limpia. ChatGPT no está tan actualizado sobre Prisma, pero la documentación oficial a menudo lo compensaba.
  • Estadísticas de la comunidad a fecha del 15 de mayo de 2023: En NPM, última actualización hace 6 días con 1,344,705 descargas semanales; en GitHub, última actualización hace 3 horas con 1.1k bifurcaciones y 31.3k estrellas.

Contras de Prisma:

  • No admite 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 unos 11,21 segundos por entrada, frente a los 2,26 segundos de Sequelize, aproximadamente 5 veces 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 las 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 la posibilidad de cambios de licencia más adelante, similar a lo que ocurrió 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 así podría ayudar a otros que estuvieran lidiando con la misma elección para sus proyectos.

El Proceso de Migración

Transformación de la Estructura de Datos

Convertir la estructura documental de MongoDB a la estructura relacional de Postgres requirió una planificación cuidadosa. Tuve que:

  1. Analizar Relaciones: Identificar cómo se relacionaban entre sí los documentos de MongoDB y diseñar relaciones de clave externa apropiadas
  2. Normalizar Datos: Descomponer documentos anidados en tablas separadas donde fuera apropiado
  3. Conservar las Funciones JSON: Usar columnas JSONB para datos verdaderamente no estructurados que necesitaban seguir siendo flexibles
  4. Diseñar Índices: Crear índices apropiados para el rendimiento de las consultas

Soluciones Personalizadas

La migración requirió desarrollar varias soluciones personalizadas:

1. Scripts de Migración de Datos Creé scripts completos para:

  • Extraer datos de las colecciones de MongoDB
  • Transformar estructuras de documentos a formato relacional
  • Importar datos en tablas de Postgres con relaciones adecuadas

2. Capa de Compatibilidad de la 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 los 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 endpoints existentes de la API siguieran 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 en relaciones de Postgres. Por ejemplo, un único documento de MongoDB podría contener:

  • Propiedades básicas
  • Objetos anidados que representan entidades relacionadas
  • Matrices de documentos incrustados

Esto tuvo que descomponerse cuidadosamente en:

  • Tablas principales para las entidades principales
  • Tablas de unión para relaciones de muchos a muchos
  • Relaciones de clave externa para asociaciones de uno a muchos

Optimización de Consultas

Los patrones de consulta de MongoDB no se traducen directamente a SQL. Tuve que:

  • Reescribir canalizaciones de agregación complejas como joins de SQL
  • Optimizar índices para nuevos patrones de consulta
  • Asegurar que el rendimiento de las consultas igualara o superara el rendimiento de MongoDB

Integridad de los Datos

Garantizar la integridad de los datos durante la migración requirió:

  • 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 y sin tiempo de inactividad, manteniendo casi todas las funciones y funcionalidades. 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 del almacenamiento más eficiente

Beneficios Operativos:

  • Capacidades mejoradas de monitoreo y depuración
  • Mejor integración con las herramientas existentes basadas en SQL de eBay
  • Procedimientos mejorados de respaldo y recuperación

Impacto en el Equipo:

  • Mayor conocimiento del equipo 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:

  • Profundo entendimiento de las funciones y la 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 primaria-respaldo

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 de 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 llevó a territorio inexplorado, 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

Capacidades de Resolución de Problemas:

  • Descomponer problemas complejos en componentes manejables
  • Desarrollar soluciones creativas para desafíos sin precedentes
  • Equilibrar múltiples requisitos y restricciones en competencia

Comunicación y Trabajo en Equipo:

  • Explicar conceptos técnicos a partes interesadas no técnicas
  • Documentar procesos y decisiones para referencia futura
  • Mentorar a miembros del equipo en nuevas tecnologías y patrones

Lecciones Aprendidas

Lecciones Técnicas

  1. La Selección de la Base de Datos Importa: La elección entre NoSQL y SQL debe basarse en casos de uso específicos y requisitos a largo plazo
  2. Las Pruebas de Rendimiento son Críticas: Las ventajas teóricas no siempre se traducen en mejoras de rendimiento en el mundo real
  3. Planificación de la Migración: La planificación y las pruebas exhaustivas son esenciales para migraciones complejas
  4. Inversión en Herramientas: Construir herramientas adecuadas desde el principio ahorra mucho tiempo y reduce errores

Lecciones de Gestión de Proyectos

  1. Comunicación con las Partes Interesadas: Las actualizaciones regulares y la comunicación clara evitan malentendidos
  2. Gestión de Riesgos: Tener planes de respaldo y procedimientos de reversión es esencial
  3. Gestión de Cronogramas: Incluir tiempo de margen para desafíos inesperados y curvas de aprendizaje
  4. 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 destaca 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:

  • Comprender el contexto completo y los requisitos antes de tomar decisiones técnicas
  • Invertir tiempo en herramientas y pruebas adecuadas
  • Mantener una comunicación clara durante 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 siguen beneficiando los proyectos de infraestructura de eBay. Reforzó mi creencia de que aceptar desafíos desconocidos y tener éxito a través de ellos es clave tanto para el desarrollo personal como profesional.

Mirando hacia atrás, este proyecto representa un punto de inflexión en mi carrera, transformándome de un desarrollador que implementa soluciones en 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 ante nuevos desafíos y oportunidades en la ingeniería de software.