MongoDB zu Postgres
🚨 Dieser Blogbeitrag ist eine Zusammenführung meiner MongoDB zu Postgres (2024-03-06) und Sequelize vs. Prisma (2023-05-25). Die ursprünglichen Blogs wurden entfernt, und dieser Blog hat ihren Platz eingenommen, da beide im Wesentlichen denselben Inhalt/Informationen enthielten. Die Migration begann im frühen März 2023, der Wechsel erfolgte im Mitte November 2023, und alle Instanzen des alten MongoDB-Systems wurden im frühen Januar 2024 vollständig abgeschaltet.
Einführung
Während meiner Zeit bei eBay stand ich vor dem technisch anspruchsvollsten Problem meiner Karriere: der Migration des Storage Management Systems (STMS) von MongoDB zu Postgres. Es war nicht nur ein einfacher Datenbankwechsel; es war eine vollständige architektonische Transformation eines kritischen Systems, das über 1,5 Millionen Metriken pro Minute in den Rechenzentren von eBay verarbeitet, mit der Anforderung von null Ausfallzeit und der Beibehaltung fast aller bestehenden Funktionen.
Was ist STMS?
Das Storage Management System (STMS) dient als kritisches internes Werkzeug für das Service & Storage Infrastructure (SSI)-Team von eBay. Es überwacht und verwaltet Geräte in den Rechenzentren von eBay und ermöglicht Ingenieuren:
- Metriken von Dutzenden von Arrays, Switches, Hosts, Disk-Gruppen und Clustern überwachen
- Alarmierung für Switches und Arrays handhaben
- Fortgeschrittene Aufgaben wie Host-Zuweisungen durchführen
- Echtzeitdaten für andere interne eBay-Dienste abrufen
STMS umfasst über 70 Arrays, 60 Switches, 1100 Hosts, 900 Disk-Gruppen und 200 Cluster in 3 der Rechenzentren von eBay. Angesichts seiner entscheidenden Rolle in der Infrastruktur von eBay würde jede Ausfallzeit oder Funktionsverlust die Kernservices und Geschäftsabläufe des Unternehmens direkt beeinträchtigen.
Die Herausforderung
Warum die Migration notwendig war
Die Entscheidung, von MongoDB zu Postgres zu migrieren, wurde nicht leichtfertig getroffen. Während MongoDB STMS anfangs gut diente, machte die wachsende Komplexität unserer Datenbeziehungen und der Bedarf an anspruchsvolleren Abfragefähigkeiten Postgres zu einer besseren langfristigen Lösung für unseren Anwendungsfall.
Was dieses Problem schwierig machte
Die Komplexität dieser Migration resultierte aus mehreren grundlegenden Herausforderungen:
1. Grundlegende Datenbankunterschiede
MongoDB und Postgres sind grundlegend unterschiedliche Datenbanken. MongoDB ist eine dokumentbasierte Datenbank (NoSQL), das heißt, Daten werden als JSON in Sammlungen gespeichert, ähnlich wie Dokumente in einem Aktenschrank. Postgres ist eine relationale Datenbank (SQL), das heißt, Daten werden als Zeilen in Tabellen gespeichert, ähnlich wie in einer Tabellenkalkulation.
2. Codebasis-Architektur
Das gesamte Backend von STMS wurde entwickelt, um Daten als JSONs zu verarbeiten und zu verwalten, wobei ausschließlich Pakete verwendet wurden, die mit MongoDB für Datenbankoperationen kompatibel sind. Das bedeutete nicht nur den Wechsel der Datenbank, sondern eine Umstrukturierung der Art und Weise, wie unsere gesamte Anwendung Daten handhabte.
3. Anforderung von null Ausfallzeit
Da STMS als internes Werkzeug so wichtig ist, durfte während der Migration keine Ausfallzeit auftreten. Das System musste während des gesamten Prozesses weiterhin über 1,5 Millionen Metriken pro Minute bereitstellen.
4. Enger Zeitplan & begrenzte Erfahrung
Die Migration musste innerhalb weniger Monate abgeschlossen werden, ohne anfänglich einen klaren Ausführungsplan. Weder ich noch meine Kollegen hatten Erfahrung mit der Migration einer großen Legacy-Codebasis von NoSQL zu SQL-Datenbanken, und ich hatte nur begrenzte Vorerfahrung mit Postgres.
5. Umfang & Komplexität
Die Migration umfasste die Umwandlung von 36 MongoDB-Collections in 74 Postgres-Tabellen, was eine sorgfältige Berücksichtigung von Beziehungen, Indexierung und Abfrageoptimierung erforderte.
Auswahl des richtigen ORM: Sequelize vs Prisma
Eine der ersten wichtigen Entscheidungen war die Auswahl eines ORM (Object-Relational Mapping)-Werkzeugs. Da unsere Codebasis bereits für die Verwendung von Mongoose mit MongoDB ausgelegt war, würde die Nutzung eines ORM den reibungslosesten Übergang ermöglichen.
Analyse der Anforderungen
Nach sorgfältiger Analyse der Projektanforderungen habe ich wesentliche Kriterien für jede ORM-Lösung festgelegt:
- Muss ein JavaScript-Paket sein (der Großteil unseres Codes wurde in JavaScript geschrieben)
- Muss Postgres und die meisten seiner Funktionen unterstützen
- Die Leistung muss mindestens gleichwertig oder besser als Mongoose sein
- Muss Open Source und gepflegt sein
Die Kandidaten
Nach umfangreicher Recherche habe ich die Auswahl auf zwei Hauptkandidaten eingegrenzt: Sequelize und Prisma. Ich erstellte umfassende Testumgebungen mit Docker für Postgres und konvertierte unseren größten, komplexesten Datensatz von der Dokumentenstruktur zur Tabellenstruktur.
Testmethodik
Für jedes ORM habe ich die Leistung bei kritischen Vorgängen gemessen:
- Zeit zum Erstellen eines Eintrags
- Zeit zum Aktualisieren eines Eintrags
- Zeit zum Aktualisieren verschachtelter Einträge (Beziehungen und JSON-Schlüsselwerte)
- Zeit zum Löschen eines Eintrags
- Zeit zum Abfragen/Abrufen eines Eintrags
Die Entscheidung: Sequelize
Um den 15. Mai 2023 entschied ich, dass Sequelize das bessere ORM für unseren Anwendungsfall war. Hier ist warum:
Vorteile von Sequelize:
- Echt Open Source und nicht von einem finanzierten Startup gepflegt
- Unterstützt die meisten Funktionen von Postgres
- Bessere Leistung, besonders im Vergleich zu Prisma
- Reifes Ökosystem mit über 10 Jahren Entwicklung
- Flexible Modell-/Schema-Darstellung mittels JavaScript-Klassen
- Unterstützung für komplexe Joins und Filteroptionen einschließlich Regex
Leistungsergebnisse:
In meinen Tests übertraf Sequelize Prisma deutlich. Für unsere großen Datensatz-Einträge:
- Sequelize: ~2,26 Sekunden pro Eintrag
- Prisma: ~11,21 Sekunden pro Eintrag
Prisma war für unseren Anwendungsfall etwa 5‑mal langsamer als Sequelize. Außerdem dauerte das Löschen eines Eintrags aus unserem größten Datensatz mit Prisma fast 4 Minuten, was für unsere Anforderungen inakzeptabel war.
Herausforderungen bei Sequelize:
- Komplexere und aufgeblähte Modell-Darstellungen (564 Zeilen vs. 262 Zeilen für Mongoose)
- Verwirrende Syntax in bestimmten Fällen
- Komplexität der Datenbankmigration
- Weniger umfassende Dokumentation im Vergleich zu Prisma
Vor- und Nachteilvergleich von Sequelize & Prisma
Um ein vollständigeres Bild zu geben, warum ich mich für Sequelize entschieden habe, möchte ich die detaillierten Vor- und Nachteile teilen, die ich für beide ORMs während meiner Bewertung zusammengestellt habe. Ich habe auch untersucht, wie sie hinsichtlich Schema-Darstellung und Community-Unterstützung zum 15. Mai 2023 abschneiden. Dieser tiefere Einblick half, meine Wahl zu festigen, und ich hoffe, er ist für andere, die vor einer ähnlichen Entscheidung stehen, nützlich.
Vorteile von Sequelize:
- Verfügt über eine sync()-Funktion, die automatisch Tabellen erstellt und verwaltet, was viel manuellen Aufwand spart.
- Kann komplexe Joins für verschachtelte Daten handhaben, was für die Struktur von STMS entscheidend war.
- Unterstützt eine breite Palette von Filteroptionen, einschließlich Regex, und bietet Flexibilität bei Abfragen.
- Modell-/Schema-Darstellung erfolgt in reinem JavaScript mittels Klassen, die stark anpassbar sind, um spezifische Bedürfnisse zu erfüllen.
- Verwaltet Datenbankverbindungen nahtlos, einschließlich Unterstützung für mehrere Leseverbindungen.
- Unterstützt rohe SQL-Abfragen, wenn man tiefer einsteigen muss.
- Community-Statistiken zum 15. Mai 2023: Auf NPM zuletzt vor 14 Tagen aktualisiert mit 1.505.835 wöchentlichen Downloads; auf GitHub zuletzt gestern aktualisiert mit 4,2 k Forks und 27,9 k Stars. Es ist seit über 10 Jahren Open Source unter einer MIT-Lizenz, daher bin ich zuversichtlich, dass es so bleibt.
Nachteile von Sequelize:
- Die Modell-/Schema-Darstellung kann sehr komplex und aufgebläht werden. Zum Beispiel war die Mongoose-Darstellung unseres großen Datensatzes etwa 262 Zeilen (inklusive Leerzeichen), während dieselbe Darstellung in Sequelize auf 564 Zeilen anwuchs.
- Die Syntax kann in bestimmten Szenarien verwirrend und kompliziert sein, was mich gelegentlich verlangsamte.
- Die Migration oder Bearbeitung der Datenbank ist mühsam. Selbst mit sequelize-cli, das Migrationsskripte erzeugt, ist es immer noch umständlich, obwohl ich festgestellt habe, dass dies ein häufiges Problem bei den meisten ORMs ist.
- Die Dokumentation ist nicht großartig, verbessert sich jedoch. Glücklicherweise haben Werkzeuge wie ChatGPT ein solides Verständnis von Sequelize aufgrund seiner langen Geschichte, was half, Lücken zu schließen.
- Nicht so typensensitiv wie Prisma, was in manchen Projekten zu Problemen führen kann.
- Begrenzte TypeScript-Unterstützung, obwohl dies für STMS kein Problem war, könnte es für andere ein entscheidender Faktor sein.
Vorteile von Prisma:
- Verwendet eine eigene Schemasprache, wodurch die Modellerstellung sauberer und prägnanter wird. Im Vergleich: Während Mongoose 262 Zeilen für unseren großen Datensatz benötigte, erledigte Prisma dies in nur 221 Zeilen.
- Kommt mit einem CLI-Tool, das die Datenbankerstellung und -migration vereinfacht, das bisher beste, das ich von einem ORM gesehen habe, auch wenn es nicht perfekt ist.
- Unterstützt rohe SQL-Abfragen und bietet bei Bedarf Flexibilität.
- Die Codesyntax ist sauberer und einfacher zu verstehen im Vergleich zu Sequelize, was das Lernen erleichtert.
- Generiert automatisch Query-Builder für Node.js und TypeScript über seinen Client, was ein nettes Feature ist.
- Hat ausgezeichnete, klare Dokumentation. ChatGPT ist nicht so aktuell zu Prisma, aber die offiziellen Docs kompensieren das oft.
- Community-Statistiken zum 15. Mai 2023: Auf NPM zuletzt vor 6 Tagen aktualisiert mit 1.344.705 wöchentlichen Downloads; auf GitHub zuletzt vor 3 Stunden aktualisiert mit 1,1 k Forks und 31,3 k Stars.
Nachteile von Prisma:
- Unterstützt kein Regex-Filtering für Postgres, bietet jedoch Alternativen wie „contains“, „includes“ und „startsWith“.
- Die Leistung war in meinen Tests ein großes Problem. Das Erstellen von Einträgen für unseren großen Datensatz dauerte bei Prisma etwa 11,21 Sekunden pro Eintrag im Vergleich zu 2,26 Sekunden bei Sequelize, also etwa 5‑mal langsamer.
- Das Löschen eines einzelnen Eintrags aus dem großen Datensatz dauerte fast 4 Minuten, was für unsere Bedürfnisse ein Ausschlusskriterium war.
- Selbst bei einem fairen Vergleich auf einem komplexen, dreischichtigen Beziehungsdatensatz war Sequelize beim Löschen deutlich schneller.
- Prisma wird von einem Startup mit 56,5 Millionen Dollar Finanzierung unterstützt. Während der Haupt-ORM-Code Open Source unter Apache‑2.0 ist, befürchte ich mögliche Lizenzänderungen in der Zukunft, ähnlich wie bei MongoDB.
Diese detaillierten Vergleiche machten deutlich, dass Sequelize besser zu den Bedürfnissen von STMS passte, insbesondere hinsichtlich Leistung und langfristiger Zuverlässigkeit. Ich dachte jedoch, dass diese Aufschlüsselung anderen helfen könnte, die vor derselben Wahl für ihre Projekte stehen.
Der Migrationsprozess
Datenstruktur-Transformation
Die Umwandlung von der Dokumentenstruktur von MongoDB in die relationale Struktur von Postgres erforderte sorgfältige Planung. Ich musste:
- Beziehungen analysieren: Identifizieren, wie MongoDB‑Dokumente zueinander in Beziehung stehen, und geeignete Fremdschlüsselbeziehungen entwerfen
- Daten normalisieren: Verschachtelte Dokumente bei Bedarf in separate Tabellen aufteilen
- JSON‑Funktionen erhalten: JSONB‑Spalten für wirklich unstrukturierte Daten verwenden, die flexibel bleiben müssen
- Indizes entwerfen: Geeignete Indizes für die Abfrageleistung erstellen
Benutzerdefinierte Lösungen
Die Migration erforderte die Entwicklung mehrerer benutzerdefinierter Lösungen:
1. Datenmigrationsskripte
Ich erstellte umfassende Skripte, um:
- Daten aus MongoDB‑Sammlungen extrahieren
- Dokumentstrukturen in ein relationales Format transformieren
- Daten in Postgres‑Tabellen mit korrekten Beziehungen importieren
2. API‑Kompatibilitätsschicht
Um Ausfallzeiten zu vermeiden, baute ich eine Kompatibilitätsschicht, die folgendes konnte:
- Anfragen je nach Migrationsstatus entweder an MongoDB oder Postgres weiterleiten
- Datenkonsistenz während der Übergangsphase sicherstellen
- Fallback‑Mechanismen bereitstellen
3. Benutzerdefinierte Middleware
Entwickelte Middleware, um die Unterschiede im Umgang von MongoDB und Postgres mit bestimmten Operationen zu bewältigen und sicherzustellen, dass bestehende API‑Endpunkte ohne Änderungen weiter funktionierten.
Überwindung technischer Herausforderungen
Umgang mit komplexen Beziehungen
Eine der größten Herausforderungen war die Umwandlung eingebetteter MongoDB‑Dokumente in Postgres‑Beziehungen. Zum Beispiel könnte ein einzelnes MongoDB‑Dokument enthalten:
- Grundlegende Eigenschaften
- Verschachtelte Objekte, die verwandte Entitäten darstellen
- Arrays eingebetteter Dokumente
Dies musste sorgfältig zerlegt werden in:
- Primärtabelle(n) für Hauptentitäten
- Verknüpfungstabellen für Viele‑zu‑Viele‑Beziehungen
- Fremdschlüsselbeziehungen für Eins‑zu‑Viele‑Assoziationen
Abfrageoptimierung
MongoDB‑Abfragemuster lassen sich nicht direkt in SQL übersetzen. Ich musste:
- Komplexe Aggregationspipelines als SQL‑Joins umschreiben
- Indizes für neue Abfragemuster optimieren
- Sicherstellen, dass die Abfrageleistung die von MongoDB erreichte Leistung erreicht oder übertrifft
Datenintegrität
Die Gewährleistung der Datenintegrität während der Migration erforderte:
- Umfassende Validierungsskripte
- Rollback‑Verfahren
- Echtzeit‑Datensynchronisation während der Übergangsphasen
Ergebnisse & Auswirkungen
Die STMS‑Migration von MongoDB zu Postgres wurde erfolgreich mit null Ausfallzeit abgeschlossen, wobei nahezu alle Funktionen und Features erhalten blieben. Die Ergebnisse übertrafen die Erwartungen:
Leistungsverbesserungen:
- Die Abfrageleistung verbesserte sich bei komplexen relationalen Abfragen
- Bessere Datenkonsistenz und -integrität
- Effizientere Speichernutzung
Betriebliche Vorteile:
- Verbesserte Überwachungs‑ und Debugging‑Funktionen
- Bessere Integration mit den bestehenden SQL‑basierten Tools von eBay
- Verbesserte Backup‑ und Wiederherstellungsprozesse
Team‑Auswirkungen:
- Erweitertes Teamwissen über relationale Datenbanken
- Etablierte Muster für zukünftige Datenbankmigrationen
- Erstellte wiederverwendbare Werkzeuge und Prozesse
Erworbenen technische Fähigkeiten
Dieses Projekt erweiterte mein technisches Fachwissen erheblich:
Datenbanktechnologien:
- Tiefes Verständnis der Postgres‑Funktionen und‑Optimierung
- SQL‑Abfrageoptimierung und Performance‑Tuning
- Datenbank‑Designmuster und Normalisierung
- Primär‑Standby‑Datenbankkonfigurationen
Entwicklungswerkzeuge:
- Sequelize ORM und Abfrageerstellung
- Datenbank‑Migrationsstrategien
- Methoden zur Leistungstests
- Datenvalidierung und Integritätsprüfung
Architekturmuster:
- Zero‑Downtime‑Migrationsstrategien
- API‑Kompatibilitätsschichten
- Datenbankabstraktionsmuster
- Überwachungs‑ und Alarmsysteme
Persönliches & berufliches Wachstum
Dieses Migrationsprojekt war transformativ für meine berufliche Entwicklung. Es brachte mich in unbekanntes Terrain und erforderte:
Führungsfähigkeiten:
- Leitung eines komplexen technischen Projekts ohne vorherige Erfahrung
- Kritische architektonische Entscheidungen unter Druck treffen
- Koordination mit mehreren Teams und Stakeholdern
Problemlösungsfähigkeiten:
- Komplexe Probleme in handhabbare Komponenten zerlegen
- Kreative Lösungen für beispiellose Herausforderungen entwickeln
- Mehrere konkurrierende Anforderungen und Einschränkungen ausbalancieren
Kommunikation & Teamarbeit:
- Technische Konzepte für nicht‑technische Stakeholder erklären
- Prozesse und Entscheidungen für die zukünftige Referenz dokumentieren
- Teammitglieder zu neuen Technologien und Mustern betreuen
Erkenntnisse
Technische Erkenntnisse
- Die Datenbankauswahl ist wichtig: Die Wahl zwischen NoSQL und SQL sollte auf spezifischen Anwendungsfällen und langfristigen Anforderungen basieren
- Leistungstests sind entscheidend: Theoretische Vorteile führen nicht immer zu realen Leistungsgewinnen
- Migrationsplanung: Umfassende Planung und Tests sind für komplexe Migrationen unerlässlich
- Investition in Werkzeuge: Der Aufbau geeigneter Werkzeuge im Vorfeld spart erheblich Zeit und reduziert Fehler
Projektmanagement‑Erkenntnisse
- Stakeholder‑Kommunikation: Regelmäßige Updates und klare Kommunikation verhindern Missverständnisse
- Risikomanagement: Das Vorhandensein von Fallback‑Plänen und Rollback‑Verfahren ist essenziell
- Zeitplanmanagement: Pufferzeit für unerwartete Herausforderungen und Lernkurven einplanen
- Dokumentation: Gründliche Dokumentation ermöglicht Wissenstransfer und zukünftige Wartung
Fazit
Die STMS‑MongoDB‑zu‑Postgres‑Migration ist das herausforderndste und lohnendste technische Problem, das ich in meiner Karriere gelöst habe. Sie erforderte nicht nur technisches Fachwissen, sondern auch Führung, Planung und Anpassungsfähigkeit. Der Erfolg des Projekts zeigte, dass mit richtiger Planung, gründlichen Tests und dem Streben nach Exzellenz selbst die komplexesten technischen Herausforderungen überwunden werden können.
Diese Erfahrung hat meine Herangehensweise an Softwareentwicklung grundlegend verändert und die Bedeutung von folgendem betont:
- Das vollständige Verständnis des Kontexts und der Anforderungen, bevor technische Entscheidungen getroffen werden
- Zeit in geeignete Werkzeuge und Tests investieren
- Klare Kommunikation während komplexer Projekte aufrechterhalten
- Die Bereitschaft, bei Bedarf neue Technologien und Ansätze zu erlernen
Der Erfolg der Migration verbesserte nicht nur die Fähigkeiten von STMS, sondern etablierte auch Muster und Prozesse, die weiterhin den Infrastrukturprojekten von eBay zugutekommen. Er bestärkte meinen Glauben, dass das Annehmen unbekannter Herausforderungen und das erfolgreiche Bewältigen derselben sowohl für die persönliche als auch die berufliche Entwicklung entscheidend ist.
Rückblickend stellt dieses Projekt einen Wendepunkt in meiner Karriere dar, der mich von einem Entwickler, der Lösungen implementiert, zu einem Ingenieur, der komplexe technische Initiativen entwerfen und leiten kann, transformierte. Das durch diese Erfahrung gewonnene Vertrauen und die Fähigkeiten leiten weiterhin meine Herangehensweise an neue Herausforderungen und Chancen in der Softwareentwicklung.