Microservices und Datenbank-Joins

112

Wie gehen Sie mit dem Rätsel um, die Datenbank aufzubrechen, wenn Sie monolithische Anwendungen in Microservices aufteilen? Typische Anwendungen, an denen ich gearbeitet habe, führen aus Gründen der Leistung und Einfachheit viele Datenbankintegrationen durch.

Wenn Sie zwei Tabellen haben, die logisch unterschiedlich sind (wenn Sie so wollen, begrenzte Kontexte), aber häufig eine aggregierte Verarbeitung für ein großes Datenvolumen durchführen, vermeiden Sie im Monolithen höchstwahrscheinlich die Objektorientierung und verwenden stattdessen den Standard Ihrer Datenbank JOIN-Funktion zum Verarbeiten der Daten in der Datenbank, bevor die aggregierte Ansicht an Ihre App-Ebene zurückgegeben wird.

Wie rechtfertigen Sie die Aufteilung solcher Daten in Microservices, bei denen Sie vermutlich die Daten über eine API und nicht über die Datenbank "verbinden" müssen?

Ich habe Sam Newmans Microservices-Buch gelesen und im Kapitel über die Aufteilung des Monolithen gibt er ein Beispiel für "Aufbrechen von Fremdschlüsselbeziehungen", in dem er anerkennt, dass ein Join über eine API langsamer sein wird - aber er fährt fort, wenn Ihre Bewerbung ist sowieso schnell genug. Ist es wichtig, dass sie langsamer als zuvor ist?

Das scheint ein bisschen glib? Was sind die Erfahrungen der Menschen? Mit welchen Techniken haben Sie die API-Verknüpfungen akzeptabel gemacht?

Martin Bayly
quelle
2
Gute Frage, ich habe das gleiche Problem und hatte am Ende eine materialisierte Sichtweise und schloss mich dem an. Ich mag es nicht, aber ich denke, das wird eine Herausforderung für Micro Services. Es gibt keinen richtigen Weg, dies zu tun, es ist nur eine Wahl des Designs. Ich weiß, dass viele Leute sagen, wir können eine materialisierte Sichtweise haben, aber aggregierte Antworten werden zu einem Problem. Lassen Sie mich wissen, wenn Sie etwas Besseres gefunden haben.
PavanSandeep
Ich weiß, dass dies alt ist, aber ist dies etwas, das graphql löst? Ich prüfe dies auch für eine segmentierte Migration, und es scheint, dass graphql der Weg ist, dies nahtlos zu machen.
themightybun
Irgendwann sollte man erkennen, dass Dogmatik nicht der richtige Weg ist. GraphQL ist ein anständiges Beispiel für die Aggregation außerhalb der Datenquelle und funktioniert normalerweise einwandfrei.
Christian Ivicevic

Antworten:

26
  • Wenn Leistung oder Latenz keine große Rolle spielen (ja, wir brauchen sie nicht immer), ist es vollkommen in Ordnung, nur einfache RESTful-APIs zum Abfragen zusätzlicher Daten zu verwenden, die Sie benötigen. Wenn Sie mehrere Aufrufe an verschiedene Microservices ausführen und ein Ergebnis zurückgeben müssen, können Sie das API-Gateway- Muster verwenden.

  • Redundanz in Polyglot-Persistenzumgebungen ist vollkommen in Ordnung . Beispielsweise können Sie die Messaging-Warteschlange für Ihre Microservices verwenden und jedes Mal "Update" -Ereignisse senden, wenn Sie etwas ändern. Andere Microservices hören die erforderlichen Ereignisse ab und speichern Daten lokal. Anstatt abzufragen, speichern Sie alle erforderlichen Daten in einem geeigneten Speicher für einen bestimmten Microservice.

  • Vergessen Sie auch nicht das Caching :) Sie können Tools wie Redis oder Memcached verwenden , um zu vermeiden, dass andere Datenbanken zu oft abgefragt werden .

sap1ens
quelle
25
Alles gute Vorschläge, aber ich finde es immer noch schwierig zu rationalisieren. Vielleicht liegt das daran, dass wir es so gewohnt sind, viel in der Datenbank zu verarbeiten. Unsere aktuelle Anwendung verfügt über komplizierte gespeicherte Prozeduren, die große Datenmengen verarbeiten und dann eine kleine Ergebnismenge zurückgeben. In einer Microservices-Architektur würde ich denken, dass diese Entitäten in verschiedene begrenzte Kontexte aufgeteilt werden sollten. Wir wissen, dass der derzeitige Ansatz hässlich ist, aber es ist schwer zu rechtfertigen, alle Daten zur Verarbeitung auf die App-Ebene zurückzubringen. Möglicherweise würde eine stärkere Denormalisierung oder Vorberechnung aggregierter Ansichten hilfreich sein.
Martin Bayly
1
Ja, ich sehe. Der Microservices-Ansatz ist nicht jedermanns Sache und sollte sorgfältig angewendet werden. Wahrscheinlich können Sie mit kleineren Änderungen beginnen.
Sap1ens
Wahrscheinlich wäre Programmierer StackExchange ein besserer Ort gewesen, um diese Frage zu stellen: programmers.stackexchange.com/questions/279409/… und andere Fragen mit dem Tag microservices programmers.stackexchange.com/questions/tagged/microservices
Martin Bayly
9

Es ist in Ordnung, dass Dienste schreibgeschützte replizierte Kopien bestimmter Referenzdaten von anderen Diensten haben.

Wenn ich versuche, eine monolithische Datenbank in Microservices umzugestalten (im Gegensatz zum Umschreiben), würde ich dies tun

  • Erstellen Sie ein Datenbankschema für den Dienst
  • Erstellen Sie versionierte * Ansichten ** in diesem Schema, um Daten aus diesem Schema für andere Dienste verfügbar zu machen
  • Verbindet sich gegen diese schreibgeschützten Ansichten

Auf diese Weise können Sie Tabellendaten / Strukturen unabhängig voneinander ändern, ohne andere Anwendungen zu beschädigen.

Anstatt Ansichten zu verwenden, könnte ich auch Trigger verwenden, um Daten von einem Schema in ein anderes zu replizieren.

Dies wäre ein schrittweiser Fortschritt in die richtige Richtung, der die Nähte Ihrer Komponenten festlegt, und ein Wechsel zu REST kann später erfolgen.

* Die Ansichten können erweitert werden. Wenn eine wichtige Änderung erforderlich ist, erstellen Sie eine Version 2 derselben Ansicht und entfernen Sie die alte Version, wenn sie nicht mehr benötigt wird. ** oder Tabellenwertfunktionen oder Sprocs.

mcintyre321
quelle
5

CQRS --- Command Query Aggregation Pattern ist die Antwort auf diese Frage gemäß Chris Richardson. Lassen Sie jeden Microservice sein eigenes Datenmodell aktualisieren und generieren Sie die Ereignisse, die die materialisierte Ansicht mit den erforderlichen Join-Daten von früheren Microservices aktualisieren. Dieses MV kann eine beliebige NoSql-Datenbank oder Redis oder Elasticsearch sein, die abfrageoptimiert ist. Diese Technik führt zu einer eventuellen Konsistenz, die definitiv nicht schlecht ist und die anwendungsseitigen Verknüpfungen in Echtzeit vermeidet. Hoffe das antwortet.

Praful
quelle
2

Ich würde die Lösungen für den Einsatzbereich trennen, beispielsweise für Betrieb und Berichterstattung.

Für die Microservices, die Daten für einzelne Formulare bereitstellen, die Daten von anderen Microservices benötigen (dies ist der Betriebsfall), ist die Verwendung von API-Joins meiner Meinung nach der richtige Weg. Sie werden keine großen Datenmengen benötigen, sondern können die Daten in den Dienst integrieren.

Der andere Fall ist, wenn Sie große Abfragen für große Datenmengen durchführen müssen, um Aggregationen usw. durchzuführen (der Berichtsfall). Für diesen Bedarf würde ich darüber nachdenken, eine gemeinsam genutzte Datenbank zu verwalten - ähnlich wie bei Ihrem ursprünglichen Schema - und sie mit Ereignissen aus Ihren Microservice-Datenbanken zu aktualisieren. In dieser gemeinsam genutzten Datenbank können Sie weiterhin Ihre gespeicherten Prozeduren verwenden, was Ihren Aufwand spart und die Datenbankoptimierungen unterstützt.

Jaro64
quelle
1

In Microservices erstellen Sie diff. Lesen Sie Modelle, also zum Beispiel: wenn Sie zwei Diff haben. Begrenzter Kontext und jemand möchte nach beiden Daten suchen, dann muss jemand Ereignisse aus beiden begrenzten Kontexten abhören und eine für die Anwendung spezifische Ansicht erstellen.

In diesem Fall wird mehr Speicherplatz benötigt, es werden jedoch keine Verknüpfungen und keine Verknüpfungen benötigt.

Techagrammer
quelle