MongoDB vers Postgres
NOTE : Cet article de blog est une fusion de mon MongoDB vers Postgres (2024-03-06) et de Sequelize vs. Prisma (2023-05-25). Les articles d’origine ont été supprimés, et ce blog les a remplacés, car les deux contenaient essentiellement le même contenu et les mêmes informations. La migration a commencé début mars 2023, le passage a eu lieu mi-novembre 2023, et toutes les instances de l’ancien système MongoDB ont été complètement arrêtées début janvier 2024.
Introduction
Pendant mon temps chez eBay, j’ai été confronté à ce qui est devenu le problème le plus difficile techniquement de ma carrière : la migration du Storage Management System (STMS) de MongoDB vers Postgres. Il ne s’agissait pas seulement d’un simple changement de base de données ; c’était une transformation architecturale complète d’un système critique qui ingère plus de 1,5 million de métriques par minute à travers les centres de données d’eBay, avec l’exigence d’aucune interruption de service et le maintien de presque toutes les fonctionnalités existantes.
Qu’est-ce que STMS ?
Le Storage Management System (STMS) sert d’outil interne critique pour l’équipe Service & Storage Infrastructure (SSI) d’eBay. Il surveille et gère les appareils à travers les centres de données d’eBay, permettant aux ingénieurs de :
- Surveiller les métriques provenant de dizaines d’array, de switches, d’hôtes, de groupes de disques et de clusters
- Gérer les alertes pour les switches et les arrays
- Réaliser des tâches avancées comme les allocations d’hôtes
- Accéder aux données en temps réel pour d’autres services internes d’eBay
STMS prend en charge plus de 70 arrays, 60 switches, 1100 hôtes, 900 groupes de disques et 200 clusters répartis dans 3 des centres de données d’eBay. Étant donné son rôle vital dans l’infrastructure d’eBay, toute interruption de service ou perte de fonctionnalité aurait un impact direct sur les services essentiels et les opérations commerciales de l’entreprise.
Le Défi
Pourquoi la migration était nécessaire
La décision de migrer de MongoDB vers Postgres n’a pas été prise à la légère. Bien que MongoDB ait bien servi STMS au départ, la complexité croissante de nos relations de données et le besoin de capacités de requête plus sophistiquées faisaient de Postgres une meilleure solution à long terme pour notre cas d’usage.
Ce qui rendait ce problème difficile
La complexité de cette migration provenait de plusieurs défis fondamentaux :
1. Différences fondamentales entre les bases de données MongoDB et Postgres sont des bases de données fondamentalement différentes. MongoDB est une base de données documentaire (NoSQL), ce qui signifie que les données sont stockées sous forme de JSON dans des collections, comme des documents dans un classeur. Postgres est une base de données relationnelle (SQL), ce qui signifie que les données sont stockées sous forme de lignes dans des tables, comme dans une feuille de calcul.
2. Architecture de la base de code Toute l’architecture backend de STMS avait été construite pour traiter et gérer les données comme des JSON, en utilisant des paquets exclusivement compatibles avec MongoDB pour les opérations de base de données. Cela signifiait qu’il ne s’agissait pas seulement de changer la base de données, mais de restructurer la façon dont toute notre application gérait les données.
3. Exigence d’absence d’interruption de service En raison du caractère vital de STMS en tant qu’outil interne, aucune interruption de service ne pouvait avoir lieu pendant la migration. Le système devait continuer à servir plus de 1,5 million de métriques par minute pendant tout le processus.
4. Calendrier serré et expérience limitée La migration devait être terminée en quelques mois, sans plan d’exécution clair au départ. Ni moi ni mes collègues n’avions d’expérience dans la migration d’une grande base de code legacy de bases NoSQL vers des bases SQL, et j’avais une expérience limitée préalable avec Postgres.
5. Échelle et complexité La migration impliquait la conversion de 36 collections MongoDB en 74 tables Postgres, nécessitant une réflexion minutieuse sur les relations, l’indexation et l’optimisation des requêtes.
Choisir le bon ORM : Sequelize vs Prisma
L’une des premières grandes décisions a été de sélectionner un outil ORM (Object-Relational Mapping). Étant donné que notre base de code était déjà conçue pour utiliser Mongoose avec MongoDB, l’utilisation d’un ORM offrirait le chemin de transition le plus fluide.
Analyse des exigences
Après une analyse approfondie des besoins du projet, j’ai établi des critères essentiels pour toute solution ORM :
- Doit être un paquet JavaScript (la majeure partie de notre code était écrite en JavaScript)
- Doit prendre en charge Postgres et la plupart de ses fonctionnalités
- Les performances doivent être au moins équivalentes à celles de Mongoose, voire meilleures
- Doit être open source et maintenu
Les candidats
Après des recherches approfondies, j’ai réduit le choix à deux principaux prétendants : Sequelize et Prisma. J’ai créé des environnements de test complets en utilisant Docker pour Postgres et j’ai converti notre plus grand jeu de données, le plus complexe, d’une structure de document à une structure de table.
Méthodologie de test
Pour chaque ORM, j’ai mesuré les performances sur des opérations critiques :
- Temps pour créer une entrée
- Temps pour mettre à jour une entrée
- Temps pour mettre à jour des entrées imbriquées (relations et paires clé-valeur JSON)
- Temps pour supprimer une entrée
- Temps pour interroger/récupérer une entrée
La décision : Sequelize
Vers le 15 mai 2023, j’ai décidé que Sequelize était le meilleur ORM pour notre cas d’usage. Voici pourquoi :
Avantages de Sequelize :
- Vraiment open source et non maintenu par une startup financée
- Prenait en charge la plupart des fonctionnalités de Postgres
- Meilleures performances, en particulier par rapport à Prisma
- Écosystème mature avec plus de 10 ans de développement
- Représentation flexible des modèles/schémas à l’aide de classes JavaScript
- Prise en charge des jointures complexes et des options de filtrage, y compris Regex
Résultats de performance :
Dans mes tests, Sequelize surpassait nettement Prisma. Pour les entrées de notre grand jeu de données :
- Sequelize : ~2,26 secondes par entrée
- Prisma : ~11,21 secondes par entrée
Prisma était environ 5 fois plus lent que Sequelize pour notre cas d’usage. De plus, supprimer une entrée de notre plus grand jeu de données prenait à Prisma près de 4 minutes, ce qui était inacceptable pour nos exigences.
Défis de Sequelize :
- Représentations de modèle plus complexes et plus lourdes (564 lignes contre 262 lignes pour Mongoose)
- Syntaxe confuse dans certains cas
- Complexité des migrations de base de données
- Documentation moins complète comparée à Prisma
Comparaison des avantages et inconvénients de Sequelize et Prisma
Pour donner une vue plus complète des raisons pour lesquelles j’ai choisi Sequelize, je veux partager les avantages et inconvénients détaillés que j’ai compilés pour les deux ORM pendant mon évaluation. J’ai également examiné leur position en termes de représentation des schémas et de soutien de la communauté au 15 mai 2023. Cette analyse plus approfondie a aidé à consolider mon choix, et j’espère qu’elle pourra être utile à toute autre personne confrontée à une décision similaire.
Avantages de Sequelize :
- Dispose d’une fonction sync() qui crée et gère automatiquement les tables pour vous, économisant beaucoup d’efforts manuels.
- Peut gérer des jointures complexes pour des données imbriquées, ce qui était essentiel pour la structure de STMS.
- Prend en charge une large gamme d’options de filtrage, y compris Regex, offrant de la flexibilité dans les requêtes.
- La représentation modèle/schéma se fait en JavaScript brut à l’aide de classes, qui sont hautement personnalisables pour répondre à des besoins spécifiques.
- Gère les connexions à la base de données de manière fluide, y compris la prise en charge de plusieurs connexions de lecture.
- Prend en charge les requêtes SQL brutes lorsque vous avez besoin de regarder sous le capot.
- Statistiques de la communauté au 15 mai 2023 : sur NPM, dernière mise à jour il y a 14 jours avec 1 505 835 téléchargements hebdomadaires ; sur GitHub, dernière mise à jour hier avec 4,2k Forks et 27,9k Étoiles. C’est open source sous licence MIT depuis plus de 10 ans, donc je suis convaincu que cela restera ainsi.
Inconvénients de Sequelize :
- La représentation modèle/schéma peut devenir très complexe et lourde. Par exemple, alors que la représentation Mongoose de notre grand jeu de données faisait environ 262 lignes (espaces compris), le même jeu de données dans Sequelize atteignait 564 lignes.
- La syntaxe peut être confuse et compliquée dans certains scénarios, ce qui m’a parfois ralenti.
- Migrer ou modifier la base de données est pénible. Même avec sequelize-cli qui génère des scripts de migration, cela reste fastidieux, bien que j’aie remarqué que c’est un point de douleur courant avec la plupart des ORM.
- La documentation n’est pas excellente, bien qu’elle s’améliore. Heureusement, des outils comme ChatGPT maîtrisent bien Sequelize grâce à sa longue histoire, ce qui a aidé à combler les lacunes.
- Moins sensible aux types que Prisma, ce qui pourrait entraîner des problèmes dans certains projets.
- Prise en charge limitée de TypeScript, bien que cela n’ait pas été un problème pour STMS, cela pourrait être rédhibitoire pour d’autres.
Avantages de Prisma :
- Utilise son propre langage de schéma, rendant la création de modèles plus propre et plus concise. À titre de comparaison, alors que Mongoose nécessitait 262 lignes pour notre grand jeu de données, Prisma l’a géré en seulement 221 lignes.
- Livré avec un outil CLI qui simplifie la création et la migration de bases de données, ce qui est le meilleur que j’aie vu jusqu’ici chez un ORM, même s’il n’est pas parfait.
- Prend en charge les requêtes SQL brutes, offrant de la flexibilité lorsque c’est nécessaire.
- La syntaxe du code est propre et plus simple à comprendre que celle de Sequelize, ce qui le rend plus facile à apprendre.
- Génère automatiquement des constructeurs de requêtes pour Node.js et TypeScript via son client, ce qui est une belle touche.
- Dispose d’une documentation excellente et claire. ChatGPT n’est pas aussi à jour sur Prisma, mais la documentation officielle compensait souvent cela.
- Statistiques de la communauté au 15 mai 2023 : sur NPM, dernière mise à jour il y a 6 jours avec 1 344 705 téléchargements hebdomadaires ; sur GitHub, dernière mise à jour il y a 3 heures avec 1,1k Forks et 31,3k Étoiles.
Inconvénients de Prisma :
- Ne prend pas en charge le filtrage Regex pour Postgres, bien qu’il propose des alternatives comme “contains”, “includes” et “startsWith.”
- Les performances étaient un problème majeur dans mes tests. Créer des entrées pour notre grand jeu de données prenait à Prisma environ 11,21 secondes par entrée contre 2,26 secondes pour Sequelize, soit environ 5 fois plus lent.
- Supprimer une seule entrée du grand jeu de données prenait près de 4 minutes, ce qui était rédhibitoire pour nos besoins.
- Même avec une comparaison équitable sur un jeu de données de relations complexes sur trois niveaux, Sequelize était nettement plus rapide pour les suppressions.
- Prisma est soutenu par une startup financée à hauteur de 56,5 millions de dollars. Bien que son code ORM principal soit open source sous Apache-2.0, je me méfie de possibles changements de licence à l’avenir, semblables à ce qui s’est produit avec MongoDB.
Ces comparaisons détaillées ont clairement montré que Sequelize correspondait mieux aux besoins de STMS, en particulier en matière de performances et de fiabilité à long terme. Mais je me suis dit que présenter les choses de cette manière pourrait aider d’autres personnes confrontées au même choix pour leurs projets.
Le processus de migration
Transformation de la structure des données
La conversion de la structure documentaire de MongoDB vers la structure relationnelle de Postgres a nécessité une planification minutieuse. J’ai dû :
- Analyser les relations : Identifier comment les documents MongoDB étaient liés les uns aux autres et concevoir des relations de clés étrangères appropriées
- Normaliser les données : Décomposer les documents imbriqués en tables séparées lorsque cela était approprié
- Préserver les fonctionnalités JSON : Utiliser des colonnes JSONB pour les données véritablement non structurées qui devaient rester flexibles
- Concevoir des index : Créer des index appropriés pour les performances des requêtes
Solutions personnalisées
La migration a nécessité le développement de plusieurs solutions personnalisées :
1. Scripts de migration des données J’ai créé des scripts complets pour :
- Extraire les données des collections MongoDB
- Transformer les structures documentaires en format relationnel
- Importer les données dans les tables Postgres avec des relations appropriées
2. Couche de compatibilité API Afin de maintenir une indisponibilité nulle, j’ai construit une couche de compatibilité capable de :
- Diriger les requêtes vers MongoDB ou Postgres selon l’état de la migration
- Garantir la cohérence des données pendant la période de transition
- Fournir des mécanismes de secours
3. Middleware personnalisé J’ai développé un middleware pour gérer les différences de traitement de certaines opérations entre MongoDB et Postgres, en veillant à ce que les points de terminaison API existants continuent de fonctionner sans modification.
Surmonter les défis techniques
Gestion de relations complexes
L’un des plus grands défis a été de convertir les documents imbriqués de MongoDB en relations Postgres. Par exemple, un seul document MongoDB pouvait contenir :
- Des propriétés de base
- Des objets imbriqués représentant des entités liées
- Des tableaux de documents imbriqués
Cela a dû être soigneusement décomposé en :
- Des tables principales pour les entités principales
- Des tables de jonction pour les relations plusieurs-à-plusieurs
- Des relations de clé étrangère pour les associations un-à-plusieurs
Optimisation des requêtes
Les modèles de requête de MongoDB ne se traduisent pas directement en SQL. J’ai dû :
- Réécrire des pipelines d’agrégation complexes sous forme de jointures SQL
- Optimiser les index pour de nouveaux modèles de requêtes
- Veiller à ce que les performances des requêtes atteignent ou dépassent celles de MongoDB
Intégrité des données
Garantir l’intégrité des données pendant la migration a nécessité :
- Des scripts de validation complets
- Des procédures de restauration
- Une synchronisation des données en temps réel pendant les périodes de transition
Résultats et impact
La migration de STMS de MongoDB vers Postgres a été menée à bien sans temps d’arrêt tout en conservant presque toutes les fonctionnalités. Les résultats ont dépassé les attentes :
Améliorations des performances :
- Les performances des requêtes se sont améliorées pour les requêtes relationnelles complexes
- Meilleure cohérence et intégrité des données
- Utilisation du stockage plus efficace
Avantages opérationnels :
- Capacités de surveillance et de débogage renforcées
- Meilleure intégration avec les outils SQL existants d’eBay
- Procédures de sauvegarde et de restauration améliorées
Impact sur l’équipe :
- Connaissances accrues de l’équipe sur les bases de données relationnelles
- Mise en place de modèles pour les futures migrations de bases de données
- Création d’outils et de processus réutilisables
Compétences techniques acquises
Ce projet a considérablement élargi mon expertise technique :
Technologies de bases de données :
- Compréhension approfondie des fonctionnalités et de l’optimisation de Postgres
- Optimisation des requêtes SQL et réglage des performances
- Modèles de conception de bases de données et normalisation
- Configurations de bases de données primaire-secondaire
Outils de développement :
- ORM Sequelize et construction de requêtes
- Stratégies de migration de bases de données
- Méthodologies de tests de performance
- Validation des données et vérification de l’intégrité
Modèles d’architecture :
- Stratégies de migration sans interruption de service
- Couches de compatibilité API
- Modèles d’abstraction de base de données
- Systèmes de surveillance et d’alerte
Développement personnel et professionnel
Ce projet de migration a été transformateur pour mon évolution de carrière. Il m’a poussé hors de ma zone de confort, nécessitant :
Compétences en leadership :
- Diriger un projet technique complexe sans expérience préalable
- Prendre des décisions architecturales critiques sous pression
- Coordonner avec plusieurs équipes et parties prenantes
Capacités de résolution de problèmes :
- Décomposer des problèmes complexes en éléments gérables
- Développer des solutions créatives à des défis sans précédent
- Équilibrer plusieurs exigences et contraintes concurrentes
Communication et travail d’équipe :
- Expliquer des concepts techniques à des parties prenantes non techniques
- Documenter les processus et les décisions pour référence future
- Encadrer les membres de l’équipe sur les nouvelles technologies et les nouveaux modèles
Leçons apprises
Leçons techniques
- Le choix de la base de données compte : Le choix entre NoSQL et SQL doit être basé sur des cas d’utilisation spécifiques et des exigences à long terme
- Les tests de performance sont essentiels : Les avantages théoriques ne se traduisent pas toujours par des gains de performance réels
- Planification de la migration : Une planification et des tests complets sont indispensables pour les migrations complexes
- Investissement dans les outils : Construire des outils adéquats dès le départ permet de gagner un temps considérable et de réduire les erreurs
Leçons de gestion de projet
- Communication avec les parties prenantes : Des mises à jour régulières et une communication claire évitent les malentendus
- Gestion des risques : Disposer de plans de secours et de procédures de restauration est essentiel
- Gestion du calendrier : Prévoir une marge pour les défis inattendus et les courbes d’apprentissage
- Documentation : Une documentation approfondie permet le transfert de connaissances et la maintenance future
Conclusion
La migration de STMS de MongoDB vers Postgres demeure le problème technique le plus difficile et le plus gratifiant que j’aie résolu dans ma carrière. Elle a nécessité non seulement une expertise technique, mais aussi du leadership, de la planification et de l’adaptabilité. Le succès du projet a démontré qu’avec une planification adéquate, des tests approfondis et un engagement envers l’excellence, même les défis techniques les plus complexes peuvent être surmontés.
Cette expérience a fondamentalement changé mon approche de l’ingénierie logicielle, en soulignant l’importance de :
- Comprendre l’ensemble du contexte et des exigences avant de prendre des décisions techniques
- Investir du temps dans des outils et des tests appropriés
- Maintenir une communication claire tout au long de projets complexes
- Être prêt à apprendre de nouvelles technologies et approches lorsque cela est nécessaire
Le succès de la migration a non seulement amélioré les capacités de STMS, mais a aussi établi des modèles et des processus qui continuent de लाभਹே profiter aux projets d’infrastructure d’eBay. Cela a renforcé ma conviction qu’affronter des défis inconnus et les surmonter est essentiel au développement personnel et professionnel.
Avec le recul, ce projet représente un tournant dans ma carrière, me transformant d’un développeur qui implémente des solutions en un ingénieur capable de concevoir et de diriger des initiatives techniques complexes. La confiance et les compétences acquises grâce à cette expérience continuent de guider mon approche des nouveaux défis et des nouvelles opportunités en ingénierie logicielle.