MongoDB zu Postgres

HINWEIS: Dieser Blogbeitrag ist eine Zusammenführung meines 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/dieselben Informationen enthielten. Die Migration begann Anfang März 2023, der Wechsel erfolgte Mitte November 2023, und alle Instanzen des alten MongoDB-Systems wurden Anfang Januar 2024 vollständig heruntergefahren.

Einführung

Während meiner Zeit bei eBay stand ich vor dem technisch herausforderndsten Problem meiner Karriere: der Migration des Storage Management Systems (STMS) von MongoDB zu Postgres. Das war nicht einfach nur ein Datenbanktausch; es war eine vollständige architektonische Transformation eines kritischen Systems, das über die Rechenzentren von eBay hinweg mehr als 1,5 Millionen Metriken pro Minute verarbeitet, mit der Anforderung von null Ausfallzeit und der Beibehaltung nahezu aller bestehenden Funktionen.

Was ist STMS?

Das Storage Management System (STMS) dient als ein entscheidendes internes Werkzeug für das Team Service & Storage Infrastructure (SSI) von eBay. Es überwacht und verwaltet Geräte in den Rechenzentren von eBay und ermöglicht es Ingenieuren:

  • Metriken von Dutzenden von Arrays, Switches, Hosts, Disk-Gruppen und Clustern zu überwachen
  • Alarmierungen für Switches und Arrays zu behandeln
  • Fortgeschrittene Aufgaben wie Host-Zuweisungen durchzuführen
  • In Echtzeit auf Daten für andere interne eBay-Dienste zuzugreifen

STMS umfasst über 70 Arrays, 60 Switches, 1100 Hosts, 900 Disk-Gruppen und 200 Cluster in 3 von eBays Rechenzentren. Angesichts seiner wichtigen Rolle in eBays Infrastruktur würde jede Ausfallzeit oder jeder Funktionsverlust die Kerndienste 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. Obwohl MongoDB STMS anfangs gut gedient hatte, machten die wachsende Komplexität unserer Datenbeziehungen und der Bedarf an ausgefeilteren Abfragefunktionen Postgres zu einer besseren langfristigen Lösung für unseren Anwendungsfall.

Was dieses Problem schwierig machte

Die Komplexität dieser Migration ergab sich aus mehreren grundlegenden Herausforderungen:

1. Grundlegende Datenbankunterschiede MongoDB und Postgres sind grundsätzlich unterschiedliche Datenbanken. MongoDB ist eine dokumentenbasierte Datenbank (NoSQL), was bedeutet, dass Daten als JSON in Sammlungen gespeichert werden, wie Dokumente in einem Aktenschrank. Postgres ist eine relationale Datenbank (SQL), was bedeutet, dass Daten als Zeilen in Tabellen gespeichert werden, wie in einer Tabellenkalkulation.

2. Architektur der Codebasis Das gesamte Backend von STMS wurde darauf aufgebaut, Daten als JSONs zu verarbeiten und zu verwalten, wobei ausschließlich mit MongoDB für Datenbankoperationen kompatible Pakete verwendet wurden. Das bedeutete nicht nur, die Datenbank zu ändern, sondern auch umzustrukturieren, wie unsere gesamte Anwendung mit Daten umging.

3. Anforderung an null Ausfallzeit Aufgrund der Wichtigkeit von STMS als internes Werkzeug durfte es während der Migration keine Ausfallzeit geben. Das System musste während des gesamten Prozesses weiterhin 1,5+ Millionen Metriken pro Minute verarbeiten.

4. Enge Zeitvorgabe & begrenzte Erfahrung Die Migration musste innerhalb weniger Monate abgeschlossen werden, anfangs ohne klaren Umsetzungsplan. Weder ich noch meine Kolleginnen und Kollegen hatten Erfahrung mit der Migration einer großen Legacy-Codebasis von NoSQL- zu SQL-Datenbanken, und ich hatte nur begrenzte frühere Erfahrung mit Postgres.

5. Umfang & Komplexität Die Migration umfasste die Umwandlung von 36 MongoDB-Sammlungen in 74 Postgres-Tabellen, was eine sorgfältige Berücksichtigung von Beziehungen, Indizierung und Abfrageoptimierung erforderte.

Die Wahl des richtigen ORMs: Sequelize vs Prisma

Eine der ersten großen Entscheidungen war die Auswahl eines ORM-Tools (Object-Relational Mapping). Da unsere Codebasis bereits so ausgelegt war, dass Mongoose für MongoDB verwendet wurde, würde der Einsatz eines ORMs den reibungslosesten Übergangspfad bieten.

Anforderungsanalyse

Nach sorgfältiger Analyse der Bedürfnisse des Projekts legte ich wesentliche Kriterien für jede ORM-Lösung fest:

  • Muss ein JavaScript-Paket sein (der Großteil unseres Codes war in JavaScript geschrieben)
  • Muss Postgres und die meisten seiner Funktionen unterstützen
  • Die Leistung muss mindestens gleich gut oder besser als die von Mongoose sein
  • Muss Open Source und gepflegt sein

Die Kandidaten

Nach umfangreicher Recherche reduzierte ich die Auswahl auf zwei Hauptkandidaten: Sequelize und Prisma. Ich erstellte umfassende Testumgebungen mit Docker für Postgres und konvertierte unseren größten und komplexesten Datensatz von einer Dokumentenstruktur in eine Tabellenstruktur.

Testmethodik

Für jedes ORM maß ich die Leistung bei kritischen Operationen:

  • Zeit zum Erstellen eines Eintrags
  • Zeit zum Aktualisieren eines Eintrags
  • Zeit zum Aktualisieren verschachtelter Einträge (Beziehungen und JSON-Key-Values)
  • Zeit zum Löschen eines Eintrags
  • Zeit zum Abfragen/Abrufen eines Eintrags

Die Entscheidung: Sequelize

Etwa am 15. Mai 2023 entschied ich, dass Sequelize das bessere ORM für unseren Anwendungsfall war. Hier ist der Grund:

Vorteile von Sequelize:

  • Wirklich Open Source und nicht von einem finanzierten Startup gepflegt
  • Unterstützte die meisten Funktionen von Postgres
  • Bessere Leistung, insbesondere im Vergleich zu Prisma
  • Reifes Ökosystem mit über 10 Jahren Entwicklung
  • Flexible Modell-/Schema-Darstellung mit JavaScript-Klassen
  • Unterstützung für komplexe Joins und Filteroptionen einschließlich Regex

Leistungsergebnisse:

In meinen Tests übertraf Sequelize Prisma deutlich. Für unsere Einträge im großen Datensatz:

  • Sequelize: ~2,26 Sekunden pro Eintrag
  • Prisma: ~11,21 Sekunden pro Eintrag

Prisma war für unseren Anwendungsfall ungefähr 5x langsamer als Sequelize. Zusätzlich dauerte das Löschen eines Eintrags aus unserem größten Datensatz bei Prisma fast 4 Minuten, was für unsere Anforderungen inakzeptabel war.

Herausforderungen mit Sequelize:

  • Komplexere und aufgeblähtere Modellrepräsentationen (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

Vergleich der Vor- und Nachteile von Sequelize & Prisma

Um ein vollständigeres Bild davon zu vermitteln, warum ich mich für Sequelize entschieden habe, möchte ich die detaillierten Vor- und Nachteile teilen, die ich während meiner Bewertung für beide ORMs zusammengestellt habe. Ich habe auch betrachtet, wie sie sich in Bezug auf Schema-Darstellung und Community-Support am 15. Mai 2023 schlugen. Dieser tiefere Einblick half, meine Entscheidung zu festigen, und ich hoffe, er könnte auch für andere hilfreich sein, die vor einer ähnlichen Entscheidung stehen.

Vorteile von Sequelize:

  • Hat eine sync()-Funktion, die Tabellen automatisch für Sie erstellt und verwaltet, wodurch viel manueller Aufwand gespart wird.
  • Kann komplexe Joins für verschachtelte Daten verarbeiten, was für die Struktur von STMS entscheidend war.
  • Unterstützt eine breite Palette von Filteroptionen, einschließlich Regex, und bietet damit Flexibilität bei Abfragen.
  • Modell-/Schema-Darstellung erfolgt in reinem JavaScript unter Verwendung von Klassen, die hochgradig anpassbar sind, um spezifische Anforderungen zu erfüllen.
  • Handhabt Datenbankverbindungen nahtlos, einschließlich Unterstützung für mehrere Read-Verbindungen.
  • Unterstützt rohe SQL-Abfragen, wenn man unter die Haube greifen muss.
  • Community-Statistiken am 15. Mai 2023: Auf NPM zuletzt vor 14 Tagen aktualisiert mit 1.505.835 wöchentlichen Downloads; auf GitHub zuletzt gestern aktualisiert mit 4,2k Forks und 27,9k Stars. Es ist seit über 10 Jahren Open Source mit einer MIT-Lizenz, daher bin ich zuversichtlich, dass es so bleiben wird.

Nachteile von Sequelize:

  • Die Modell-/Schema-Darstellung kann sehr komplex und aufgebläht werden. Während die Mongoose-Darstellung unseres großen Datensatzes etwa 262 Zeilen umfasste (einschließlich Leerzeichen), wuchs derselbe Datensatz in Sequelize auf 564 Zeilen an.
  • Die Syntax kann in bestimmten Szenarien verwirrend und kompliziert sein, was mich zeitweise ausbremste.
  • Das Migrieren oder Bearbeiten der Datenbank ist mühsam. Selbst mit von sequelize-cli generierten Migrationsskripten ist es immer noch umständlich, obwohl ich bemerkt habe, dass dies bei den meisten ORMs ein häufiger Schmerzpunkt ist.
  • Die Dokumentation ist nicht großartig, obwohl sie besser wird. Glücklicherweise verstehen Tools wie ChatGPT Sequelize aufgrund seiner langen Geschichte recht gut, was half, Lücken zu schließen.
  • Nicht so typsensitiv wie Prisma, was in manchen Projekten zu Problemen führen könnte.
  • Begrenzte TypeScript-Unterstützung; obwohl dies für STMS kein Problem war, könnte es für andere ein K.-o.-Kriterium sein.

Vorteile von Prisma:

  • Verwendet eine eigene Schemasprache, wodurch die Modellerstellung sauberer und kompakter wird. Zum Vergleich: Während Mongoose für unseren großen Datensatz 262 Zeilen benötigte, schaffte Prisma es mit nur 221 Zeilen.
  • Kommt mit einem CLI-Tool, das die Datenbankerstellung und -migration vereinfacht, was das Beste ist, das ich bisher bei einem ORM gesehen habe, auch wenn es nicht perfekt ist.
  • Unterstützt rohe SQL-Abfragen und bietet bei Bedarf Flexibilität.
  • Der Codesyntax ist im Vergleich zu Sequelize sauber und einfacher zu verstehen, was das Lernen erleichtert.
  • Generiert über seinen Client automatisch Query-Builder für Node.js und TypeScript, was eine nette Ergänzung ist.
  • Hat eine ausgezeichnete, saubere Dokumentation. ChatGPT ist bei Prisma nicht so aktuell, aber die offizielle Dokumentation machte das oft wett.
  • Community-Statistiken am 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,1k Forks und 31,3k Stars.

Nachteile von Prisma:

  • Unterstützt für Postgres kein Regex-Filtering, bietet aber 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 gegenüber 2,26 Sekunden bei Sequelize, also ungefähr 5x langsamer.
  • Das Löschen eines einzelnen Eintrags aus dem großen Datensatz dauerte fast 4 Minuten, was für unsere Anforderungen ein Ausschlusskriterium war.
  • Selbst bei einem fairen Vergleich auf einem komplexen, drei Ebenen tiefen Beziehungsdatensatz war Sequelize beim Löschen deutlich schneller.
  • Prisma wird von einem Startup mit 56,5 Millionen US-Dollar Finanzierung unterstützt. Während der Haupt-ORM-Code unter Apache-2.0 Open Source ist, bin ich hinsichtlich möglicher Lizenzänderungen in der Zukunft vorsichtig, ähnlich wie es bei MongoDB passiert ist.

Diese detaillierten Vergleiche machten klar, dass Sequelize besser zu den Bedürfnissen von STMS passte, insbesondere in Bezug auf Leistung und langfristige Zuverlässigkeit. Aber ich dachte mir, es könnte anderen helfen, die mit derselben Wahl für ihre Projekte ringen, wenn ich es so aufschlüssle.

Der Migrationsprozess

Transformation der Datenstruktur

Die Umwandlung von MONGODBs Dokumentenstruktur in die relationale Struktur von Postgres erforderte sorgfältige Planung. Ich musste:

  1. Beziehungen analysieren: Identifizieren, wie MongoDB-Dokumente miteinander in Beziehung standen, und geeignete Foreign-Key-Beziehungen entwerfen
  2. Daten normalisieren: Verschachtelte Dokumente gegebenenfalls in separate Tabellen aufteilen
  3. JSON-Funktionen beibehalten: JSONB-Spalten für wirklich unstrukturierte Daten verwenden, die flexibel bleiben mussten
  4. Indizes entwerfen: Geeignete Indizes für die Abfrageleistung erstellen

Benutzerdefinierte Lösungen

Die Migration erforderte die Entwicklung mehrerer benutzerdefinierter Lösungen:

1. Datemigrationsskripte Ich erstellte umfassende Skripte, um:

  • Daten aus MongoDB-Sammlungen extrahieren
  • Dokumentenstrukturen in ein relationales Format umwandeln
  • Daten mit korrekten Beziehungen in Postgres-Tabellen importieren

2. API-Kompatibilitätsschicht Um Ausfallzeiten von null beizubehalten, baute ich eine Kompatibilitätsschicht, die:

  • Anfragen je nach Migrationsstatus entweder an MongoDB oder Postgres weiterleiten konnte
  • Während der Übergangsphase die Datenkonsistenz sicherstellte
  • Fallback-Mechanismen bereitstellte

3. Benutzerdefinierte Middleware Es wurde Middleware entwickelt, um die Unterschiede in der Art und Weise zu handhaben, wie MongoDB und Postgres bestimmte Operationen verarbeiten, und sicherzustellen, dass bestehende API-Endpunkte weiterhin ohne Änderungen funktionierten.

Überwindung technischer Herausforderungen

Umgang mit komplexen Beziehungen

Eine der größten Herausforderungen war die Umwandlung von MongoDBs eingebetteten Dokumenten in Postgres-Beziehungen. Ein einzelnes MongoDB-Dokument könnte zum Beispiel enthalten:

  • Grundlegende Eigenschaften
  • Verschachtelte Objekte, die verbundene Entitäten darstellen
  • Arrays eingebetteter Dokumente

Dies musste sorgfältig zerlegt werden in:

  • Primärtabellen für Haupteinheiten
  • Junction-Tabellen für Viele-zu-viele-Beziehungen
  • Foreign-Key-Beziehungen für Eins-zu-viele-Zuordnungen

Abfrageoptimierung

MongoDBs Abfragemuster lassen sich nicht direkt auf SQL übertragen. Ich musste:

  • Komplexe Aggregations-Pipelines als SQL-Joins neu schreiben
  • Indizes für neue Abfragemuster optimieren
  • Sicherstellen, dass die Abfrageleistung die Leistung von MongoDB erreichte oder übertraf

Datenintegrität

Die Sicherstellung der Datenintegrität während der Migration erforderte:

  • Umfassende Validierungsskripte
  • Rücksetzungsverfahren
  • Echtzeit-Datensynchronisierung während der Übergangsphasen

Ergebnisse & Auswirkungen

Die STMS-Migration von MongoDB zu Postgres wurde erfolgreich mit null Ausfallzeiten abgeschlossen, während nahezu alle Funktionen und die gesamte Funktionalität erhalten blieben. Die Ergebnisse übertrafen die Erwartungen:

Leistungsverbesserungen:

  • Die Abfrageleistung verbesserte sich für komplexe relationale Abfragen
  • Bessere Datenkonsistenz und -integrität
  • Effizientere Speichernutzung

Betriebliche Vorteile:

  • Verbesserte Monitoring- und Debugging-Fähigkeiten
  • Bessere Integration mit eBays bestehenden SQL-basierten Tools
  • Verbesserte Backup- und Wiederherstellungsverfahren

Auswirkungen auf das Team:

  • Erweitertes Wissen des Teams über relationale Datenbanken
  • Etablierte Muster für zukünftige Datenbankmigrationen
  • Wiederverwendbare Tools und Prozesse geschaffen

Erlernte technische Fähigkeiten

Dieses Projekt erweiterte mein technisches Fachwissen erheblich:

Datenbanktechnologien:

  • Tiefes Verständnis der Postgres-Funktionen und -Optimierung
  • SQL-Abfrageoptimierung und Leistungsabstimmung
  • Datenbankentwurfsmuster und Normalisierung
  • Primär-Standby-Datenbankkonfigurationen

Entwicklungstools:

  • Sequelize ORM und Abfrageerstellung
  • Strategien für Datenbankmigrationen
  • Methoden für Leistungstests
  • Datenvalidierung und Integritätsprüfung

Architekturmuster:

  • Strategien für Ausfallzeit-freie Migrationen
  • API-Kompatibilitätsschichten
  • Datenbank-Abstraktionsmuster
  • Monitoring- und Alarmsysteme

Persönliches und berufliches Wachstum

Dieses Migrationsprojekt war für meine berufliche Entwicklung transformativ. Es führte mich in unerforschtes Terrain und erforderte:

Führungsfähigkeiten:

  • Leitung eines komplexen technischen Projekts ohne vorherige Erfahrung
  • Treffen kritischer Architekturentscheidungen unter Druck
  • Koordination mit mehreren Teams und Stakeholdern

Problemlösungsfähigkeiten:

  • Aufteilung komplexer Probleme in handhabbare Komponenten
  • Entwicklung kreativer Lösungen für beispiellose Herausforderungen
  • Abwägung mehrerer konkurrierender Anforderungen und Zwänge

Kommunikation & Teamarbeit:

  • Erläuterung technischer Konzepte für nicht-technische Stakeholder
  • Dokumentation von Prozessen und Entscheidungen für zukünftige Referenzen
  • Mentoring von Teammitgliedern bei neuen Technologien und Mustern

Gelernte Lektionen

Technische Lektionen

  1. Die Wahl der Datenbank ist wichtig: Die Entscheidung zwischen NoSQL und SQL sollte auf spezifischen Anwendungsfällen und langfristigen Anforderungen basieren
  2. Leistungstests sind kritisch: Theoretische Vorteile führen nicht immer zu realen Leistungsgewinnen
  3. Migrationsplanung: Umfassende Planung und Tests sind für komplexe Migrationen unerlässlich
  4. Investition in Tooling: Der frühzeitige Aufbau geeigneter Werkzeuge spart erheblich Zeit und reduziert Fehler

Lektionen zum Projektmanagement

  1. Stakeholder-Kommunikation: Regelmäßige Updates und klare Kommunikation verhindern Missverständnisse
  2. Risikomanagement: Backup-Pläne und Rücksetzungsverfahren sind unerlässlich
  3. Zeitplanmanagement: Pufferzeit für unerwartete Herausforderungen und Lernkurven einplanen
  4. Dokumentation: Gründliche Dokumentation ermöglicht Wissenstransfer und zukünftige Wartung

Fazit

Die STMS-Migration von MongoDB zu Postgres ist das technisch anspruchsvollste und zugleich lohnendste 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 selbst die komplexesten technischen Herausforderungen mit guter Planung, gründlichen Tests und dem Streben nach Exzellenz überwunden werden können.

Diese Erfahrung veränderte meinen Ansatz in der Softwareentwicklung grundlegend und betonte die Bedeutung von:

  • Den vollständigen Kontext und die Anforderungen zu verstehen, bevor technische Entscheidungen getroffen werden
  • Zeit in geeignetes Tooling und Tests zu investieren
  • Während komplexer Projekte eine klare Kommunikation aufrechtzuerhalten
  • Bei Bedarf bereit zu sein, 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 EBay’s Infrastrukturprojekte unterstützen. Er bestärkte meinen Glauben daran, dass das Annehmen unbekannter Herausforderungen und das Bestehen dabei der Schlüssel sowohl zur persönlichen als auch zur beruflichen Entwicklung ist.

Rückblickend stellt dieses Projekt einen Wendepunkt in meiner Karriere dar und verwandelte mich von einem Entwickler, der Lösungen implementiert, in einen Ingenieur, der komplexe technische Initiativen architektieren und leiten kann. Das aus dieser Erfahrung gewonnene Selbstvertrauen und die erworbenen Fähigkeiten leiten weiterhin meinen Umgang mit neuen Herausforderungen und Chancen in der Softwareentwicklung.