Benutzeraktionsdienst: Vom Monolithen zur Cloud

(Souhaib Guitouni) (23. Juni 2020)

Einführung

Historisch gesehen war das Backend von BlaBlaCar ein großer PHP-Monolith. Es ermöglichte uns, Features schnell zu iterieren und zu erstellen, aber auf lange Sicht war es nicht einfach, sie zu erfassen, zu warten und weiterzuentwickeln. In den letzten Jahren haben wir diesen alten Monolithen zerstört und uns einer serviceorientierten Architektur zugewandt.

Dieser Artikel ist eine der Geschichten darüber, wie wir diesen Übergang bewältigen, mit einigen Details zum Werkzeuge, die uns dabei geholfen haben. Es wird die Auswahl des technischen Stacks, die allgemeine Architektur und das Feedback zu den von uns verwendeten Tools behandeln.

I – Das Warum

Mit der Erweiterung der Aktivität von BlaBlaCar wird eine monolithische Architektur immer mehr Einschränkung, hauptsächlich, weil:

  • Monolithen während ihres Lebens in Kopplung geraten;
  • Es ist schwierig, Teams, die an separaten Rückständen arbeiten, auf derselben Codebasis zu organisieren;
  • Monolithen sind für Neulinge schwer zu verstehen;
  • Bei alledem wird jede neue Funktionalität extrem kostspielig.

Aus diesem Grund haben wir in den letzten Jahren unsere Plattform auf eine SOA-Architektur umgestaltet. Suchen nach:

  • Server mit funktionalem Gültigkeitsbereich: Ein Dienst verwaltet eine einzelne Funktionalität und ist voll verantwortlich für deren Implementierung.
  • Locker gekoppelte Dienste, die sich unabhängig voneinander entwickeln können. Teams können in ihrem eigenen Tempo arbeiten und bereitstellen.
  • Mehr Code-Besitz, sodass Services einen definierten und reduzierten Umfang haben, sodass Teams sie einfacher warten und bedienen können.

II – Umfang und Verlauf der Benutzeraktionen

Die letzten Aktionen, die zu einem unabhängigen Dienst gemacht werden sollten, waren die Benutzeraktionen. Sie helfen unserem Community Relations-Team, Benutzerprobleme zu diagnostizieren und zu lösen, z. B. Rückerstattungen zu gewähren und Anomalien zu erkennen oder betrügerisches Verhalten zu verfolgen.

Die Anzahl der Benutzeraktionen ist erwartungsgemäß enorm. In der Vergangenheit hatte dieser Teil des Codes als eine SQL-Tabelle Leistungsprobleme. Wir haben jedes Mal Lösungen gefunden, aber mit unserer Erweiterung wurden die Probleme immer größer:

  • Eine erste Lösung bestand darin, Indizes zu erstellen, um Abfragen schneller zu machen;
  • Eine andere bestand darin, Shards zu erstellen Die Datenbank in mehrere Tabellen aufteilen.

Trotzdem stießen diese Lösungen an ihre Grenzen und mit der Zeit traten Leistungsprobleme auf.

III – Datenspeicherung

1 – Der Weg zu NoSQL

Die Auswahl des Datenspeichers basierte hauptsächlich auf technischen Daten Anforderungen:

  • Es gibt große Datenmengen
  • Große Anzahl von Einfügungen
  • Mehrere Lesevorgänge pro Sekunde, wobei neue Daten und Leistung erforderlich sind
  • Möglichkeit, in angemessener Zeit zu filtern

Wir suchten offensichtlich nach einer NoSQL-Datenbank, da die Verteilung es uns ermöglichen würde, große Datenmengen zu speichern und zu bearbeiten und zu skalieren, wann benötigt.

2 – Verwalteter Dienst

Wir wollten auch gehen mit einem verwalteten Service, um die Wartungskosten zu senken. Verteilte Datenbanken wie Hbase und Cassandra sind bekannt für die Schwierigkeiten, die sie den Datenbankverwaltungsteams bereiten. Noch wichtiger ist, dass wir uns für das Anwendungsentwicklungsteam darauf konzentrieren wollten, die Logik der Handhabung von Benutzeraktionen zu entwickeln, anstatt unsere Zeit damit zu verbringen, Probleme mit der Datenbankinfrastruktur zu beheben. Es war auch die Gelegenheit, ein neues Produkt zu testen, da der Anwendungsbereich nicht zu groß ist. Wir wollten etwas Neues ausprobieren!

3 – Endgültige Auswahl

Die Auswahl fiel aus folgenden Gründen auf Bigtable:

  • Volumen: Es wurde entwickelt, um große Datenmengen zu verarbeiten. Im Gegensatz zu den meisten SQL-Datenbanken kann eine Instanz 10.000 Einfügungen pro Sekunde verarbeiten Die minimale Konfiguration mit nur drei Knoten.
  • Skalierbarkeit: Es ist skalierbar und einfach zu replizieren. Sie können auch Datenversionen verwalten.
  • Verwaltungskosten: Es handelt sich um einen verwalteten Dienst.
  • Leistung: Es handelt sich um einen GCP-Dienst, mit dem wir eine hervorragende Leistung erzielen können, da er sich in derselben Infrastruktur befindet wie der in GKE bereitgestellte Dienst.

III – Von einem fahrenden Zug zum anderen springen

Das Schwierige daran Der Wechsel von einem Monolithen zu einem Dienst bedeutet, die Kontinuität des Dienstes von außen zu gewährleisten und keinen Datenverlust zu verursachen.

Um dies zu gewährleisten, haben wir beschlossen, den neuen Dienst auszuführen, das alte System funktionsfähig zu halten und die neuen Aktionen über REST in beide zu schreiben. Der nächste Schritt besteht darin, die historischen Daten vom Monolithen in den neuen Dienst zu verschieben. Diese Operation kann zu Doppelwerten führen, sodass das anfängliche Laden der Daten die Deduplizierung übernehmen sollte. Ein dritter Schritt besteht darin, vom neuen Dienst anstelle des alten Systems zu lesen. Ein letzter Schritt wäre das Herunterfahren des Monolith-Teils und der alten SQL-Datenbank, sobald alles im Dienst funktioniert.

IV – Verschieben von Daten

1 – Von MySQL zu Bigtable

Nachdem wir uns entschieden hatten, wie unser Zieldatenspeicher aussehen und wie er bereitgestellt werden soll, begannen wir darüber nachzudenken die Möglichkeiten, Daten vom Monolithen in die neue Datenbank zu verschieben. Ein solcher Vorgang ist von entscheidender Bedeutung, und der Migrationsjob sollte wie folgt aussehen:

  • Einfach und leicht zu entwickeln: Die Komplexität der Datenbankkonnektoren
  • Hochleistungsfähig: da er sehr umfangreich sein wird Datenmengen, wir möchten das Ergebnis so schnell wie möglich haben.
  • Zuverlässig: Wir wollten keinen Datenverlust.
  • Einfach neu zu starten: Für den Fall, dass etwas schief geht, wollten wir etwas, das wir könnten Starten Sie einfach ohne viele manuelle Aktionen neu, mit Shell-Skripten überall und einer komplexen Prozedur.
  • Ermöglichen von Transformationen: Wir mussten Daten aus mehreren MySQL-Datenbanken und -Tabellen zusammenführen, um die endgültigen Bigtable-Datenbanken zu erhalten. Dies könnte schwierig sein, wenn manuell geschrieben.

2 – Apache Beam und Datenfluss

Wir haben uns für Dataflow entschieden, einen verteilten verwalteten Dienst von Google Cloud, mit dem Benutzer Daten im Batch- und im Streaming-Modus verschieben können.

Apache Beam hingegen ist ein Framework zum Codieren verteilter Skripts . Sie können es dann auf vielen verteilten Engines wie Dataflow, Spark, Flink … ausführen. Mit anderen Worten, es ist eine Abstraktionsschicht, um Ihre Transformationen zu definieren, die von mehreren Engines verstanden werden können.

Eine weitere coole Sache bei Apache Beam ist Es verfügt über sofort einsatzbereite Anschlüsse für mehrere Datenquellen, darunter MySQL und Bigtable. Also haben wir die Datentransformationen erstellt, aus MySQL-Legacy-Tabellen gelesen, sie zusammengefügt und das Ergebnis in Bigtable eingefügt.

2 – Wie ist es gelaufen?

Während der Migration haben wir einige Beobachtungen gemacht:

  • Es war eine anstrengende Aufgabe für MySQL: Leistungsprobleme zu vermeiden, Sie müssen auf jeden Fall vermeiden, es in einer kritischen Datenbank auszuführen. Um dieses Problem zu vermeiden, haben wir es in einer Replikatdatenbank ausgeführt, die für solche Aufgaben erstellt wurde. Wir verfolgten die Ausführung unseres Überwachungsdienstes (Prometheus / Grafana), der zeigte, dass parallele Dataflow-Maschinen MySQL erschöpfen.
  • Auch für Bigtable war es nicht einfach: Wir hatten eine kleine Instanz von 3 Maschinen, die 30.000 Einfügungen liefern konnten pro Sekunde. Wenn Sie mehrere Dataflow-Jobs ausführen, gehen Sie weit darüber hinaus. Überlegen Sie sich also genau, wie viele Computer Sie parallel haben möchten, da Sie mit der maximalen Anzahl Geld verlieren.
  • Der MySQL Beam-Connector überträgt keine Daten: Der MySQL-Connector führt eine SQL-Anweisung aus und wartet um die gesamte Antwort zu laden und fortzufahren. Dies führt zu Problemen mit dem RAM, wenn Sie viele Daten laden. Sie müssen also die Benutzerbereiche testen und definieren, um eine Speicherausnahme zu vermeiden.

V – Der Backend-Dienst

Wir waren mehrere Architekturmuster möglich wollte mit einer Architektur arbeiten, die sich in Zukunft weiterentwickeln kann und die wir Schritt für Schritt mit Live-Verkehr vom ersten Schritt an erstellen können.

Wir haben beschlossen, einen Dienst mit Spring WebFlux, dem reaktiven Framework, zu erstellen , um nicht blockierende Anforderungen zu haben und dann eine bessere Leistung mit funktionalen Endpunkten zu erzielen. Wir haben Reactor für die beste Integration mit Spring verwendet.

1 – Integrationstests mit Bigtable

Integrationstests rufen die API mit mehreren Nutzdaten / Headern auf und prüfen, ob die Antwort wie erwartet ist. Dazu benötigten wir eine Bigtable-Instanz hinter unserem Service, da wir Tests im realen Leben wollten.

Diese Instanz muss bei jedem Lauf bereinigt werden, um jedes Mal mit demselben Status zu beginnen.

Die Lösung bestand darin, den im Bigtable-Client-SDK vorhandenen Bigtable-Emulator zu verwenden. Das SDK ist sehr umfangreich und verfügt über weitere Funktionen wie Administratorverwaltung und -überwachung.

2 – Bereitstellung und Infrastruktur

Unsere GCP-Infrastruktur basiert auf Google Kubernetes und Istio. Wir schaffen das Ganze mit Helm und Flux. Weitere Artikel finden Sie in unserem Blog, um mehr über unsere Infrastruktur zu erfahren!

Natürlich hatte unser Service klassische Überwachungs-, Protokollierungs- und Alarmierungsziele, ohne die wir ihn nicht live ausführen könnten , basierend auf Prometheus / Grafana und ELK.

Letzte Gedanken

Um die großen Datenmengen zu verwalten, haben wir uns dank der Skalierbarkeit für Bigtable entschieden.Wir hatten mehrere Herausforderungen wie das Definieren des Datenschemas mit dem Bigtable-Schlüsselmuster, das Verschieben großer Datenmengen von einer SQL-On-Premise-Datenbank in ein verwaltetes NoSQL, das Testen und Überwachen des Ganzen.

Zuerst haben wir den Service bereitgestellt In unserem lokalen Rechenzentrum und durch den Wechsel zu GCP haben wir die Latenz durch drei geteilt. Unsere Community Relations-Teams haben jetzt schnellere Reaktionszeiten und sind begeistert.