Eine Anleitung zum Verständnis von Datenbankskalierungsmustern

Es gibt viele Artikel online, die Muster der Skalierbarkeit von Datenbanken beschreiben, aber es handelt sich meistens um verstreute Artikel - nur Techniken, die willkürlich ohne viel Kontext definiert werden. Ich finde, dass sie nicht Schritt für Schritt definiert werden, und diskutiere nicht, wann man welche Skalierungsoption wählt, welche Skalierungsoptionen in der Praxis machbar sind und warum.

Daher plane ich, einige der Techniken in zukünftigen Artikeln ausführlich zu diskutieren. Zunächst finde ich es besser, wenn ich Schritt für Schritt Techniken mit einem bestimmten Kontext auf meine eigene Weise diskutiere. Dieser Artikel ist ein Artikel auf hoher Ebene. Ich werde hier nicht detailliert auf Skalierungstechniken eingehen, sondern einen Überblick geben. Also lasst uns anfangen.

Eine Fallstudie

Angenommen, Sie haben ein Startup aufgebaut, das Mitfahrgelegenheiten zu günstigen Kosten anbietet. Wenn Sie anfangen, zielen Sie zunächst auf eine Stadt ab und haben nach Ihrer ersten Werbung kaum zehn Kunden.

Sie speichern alle Kunden, Reisen, Standorte, Buchungsdaten und den Kundenreiseverlauf in derselben Datenbank oder höchstwahrscheinlich auf einer einzigen physischen Maschine. Es gibt kein ausgefallenes Caching oder eine Big-Data-Pipeline, um Probleme zu lösen, da Ihre App sehr neu ist. Dies ist derzeit perfekt für Ihren Anwendungsfall, da es nur sehr wenige Kunden gibt und Ihr System beispielsweise kaum eine Fahrt in 5 Minuten bucht.

Mit der Zeit melden sich jedoch immer mehr Menschen in Ihrem System an, da Sie der billigste Dienst auf dem Markt sind und dank Ihrer Werbung und Anzeigen. Sie buchen beispielsweise 10 Buchungen pro Minute und langsam steigt die Anzahl auf 20, 30 Buchungen pro Minute.

Zu diesem Zeitpunkt stellen Sie fest, dass das System eine schlechte Leistung aufweist: Die API-Latenz hat stark zugenommen, und einige Transaktionen blockieren oder verhungern und scheitern schließlich. Ihre App benötigt mehr Zeit, um zu reagieren, was zu Unzufriedenheit bei den Kunden führt. Was können Sie tun, um das Problem zu lösen?

Muster 1 - Implementierung des Abfrageoptimierungs- und Verbindungspools:

Die erste Lösung ist, dass der Cache häufig nicht dynamische Daten wie Buchungsverlauf, Zahlungsverlauf, Benutzerprofile usw. verwendet. Nach diesem Caching auf Anwendungsebene können Sie jedoch das Latenzproblem von APIs nicht lösen, die dynamische Daten wie den aktuellen Fahrerstandort oder die nächstgelegenen Kabinen für einen bestimmten Kunden oder die aktuellen Reisekosten zu einem bestimmten Zeitpunkt nach Reiseantritt verfügbar machen.

Sie stellen fest, dass Ihre Datenbank wahrscheinlich stark normalisiert ist, und fügen daher aus Gründen der Denormalisierung einige redundante Spalten (diese Spalten erscheinen häufig in WHEREoder JOIN ONKlauseln in Abfragen) in häufig verwendeten Tabellen ein. Dies reduziert Verknüpfungsabfragen, unterteilt eine große Abfrage in mehrere kleinere Abfragen und addiert deren Ergebnisse in der Anwendungsschicht.

Eine weitere parallele Optimierung, die Sie durchführen können, ist das Optimieren von Datenbankverbindungen. Datenbank-Client-Bibliotheken und externe Bibliotheken sind in fast allen Programmiersprachen verfügbar. Sie können Verbindungspoolbibliotheken zum Zwischenspeichern von Datenbankverbindungen verwenden oder die Größe des Verbindungspools im Datenbankverwaltungssystem selbst konfigurieren.

Das Herstellen einer Netzwerkverbindung ist kostspielig, da eine gewisse Kommunikation zwischen Client und Server erforderlich ist. Durch das Zusammenlegen von Verbindungen können Sie die Anzahl der Verbindungen optimieren. Verbindungspoolbibliotheken können Ihnen beim Multiplexen von Verbindungen helfen - mehrere Anwendungsthreads können dieselbe Datenbankverbindung verwenden. Ich werde später in einem separaten Artikel sehen, ob ich das Verbindungspooling ausführlich erläutern kann.

Sie messen die Latenz Ihrer APIs und stellen wahrscheinlich eine reduzierte Latenz von 20–50% oder mehr fest. Dies ist zu diesem Zeitpunkt eine gute Optimierung.

Sie haben Ihr Unternehmen jetzt auf eine weitere Stadt skaliert, mehr Kunden haben sich angemeldet und beginnen langsam mit 80 bis 100 Buchungen pro Minute. Ihr System kann diese Skala nicht verarbeiten. Sie sehen erneut, dass die API-Latenz zugenommen hat, die Datenbankschicht aufgegeben hat, aber diesmal bringt Ihnen keine Abfrageoptimierung einen signifikanten Leistungsgewinn. Sie überprüfen die Systemmetrik, stellen fest, dass der Speicherplatz fast voll ist, die CPU zu 80% ausgelastet ist und der Arbeitsspeicher sehr schnell voll ist.

Muster 2 - Vertikale Skalierung oder Skalierung:

Nachdem Sie alle Systemmetriken überprüft haben, wissen Sie, dass es keine andere einfache Lösung gibt, als die Hardware des Systems zu aktualisieren. Sie aktualisieren Ihre RAM-Größe um das Zweifache, den Speicherplatz beispielsweise um das Dreifache oder mehr. Dies wird als vertikale Skalierung oder Skalierung Ihres Systems bezeichnet. Sie informieren Ihr Infrastruktur-Team oder das Entwicklerteam oder Rechenzentrumsagenten von Drittanbietern, um Ihren Computer zu aktualisieren.

Aber wie richten Sie die Maschine für die vertikale Skalierung ein?

Sie weisen eine größere Maschine zu. Ein Ansatz besteht nicht darin, Daten manuell vom alten Computer zu migrieren, sondern den neuen Computer replicaauf den vorhandenen Computer ( primary) festzulegen primary replica. Erstellen Sie eine temporäre Konfiguration. Lassen Sie die Replikation natürlich geschehen. Sobald die Replikation abgeschlossen ist, stellen Sie den neuen Computer auf den primären Computer und schalten Sie den älteren Computer offline. Da von der größeren Maschine erwartet wird, dass sie alle Anforderungen erfüllt, werden alle Lese- / Schreibvorgänge auf dieser Maschine ausgeführt.

Cool. Ihr System ist mit erhöhter Leistung wieder betriebsbereit.

Ihr Geschäft läuft sehr gut und Sie entscheiden sich für eine Skalierung auf 3 weitere Städte - Sie sind jetzt in insgesamt 5 Städten tätig. Der Verkehr ist dreimal so groß wie früher. Es wird erwartet, dass Sie ungefähr 300 Buchungen pro Minute vornehmen. Bevor Sie diese Zielbuchung überhaupt erreichen, stoßen Sie erneut auf die Leistungskrise. Die Größe des Datenbankindex nimmt im Speicher stark zu, muss ständig gewartet werden. Das Scannen von Tabellen mit Index wird langsamer als je zuvor. Sie berechnen die Kosten für die weitere Skalierung der Maschine, sind jedoch nicht von den Kosten überzeugt. Was tust du jetzt?

Muster 3 - CQRS (Command Query Responsibility Segregation):

Sie stellen fest, dass die große Maschine nicht alle read/writeAnforderungen verarbeiten kann. In den meisten Fällen benötigt jedes Unternehmen Transaktionsfähigkeiten writefür den readBetrieb, jedoch nicht für den Betrieb. Sie sind auch in Ordnung mit ein wenig inkonsistenten oder verzögerten readVorgängen und Ihr Unternehmen hat auch damit kein Problem. Sie sehen eine Möglichkeit, bei der es eine gute Option sein könnte, die physische Maschine read& writeOperations zu trennen . Es wird Spielraum für einzelne Maschinen schaffen, um mehr read/writeOperationen abzuwickeln.

Sie nehmen jetzt zwei weitere große Maschinen und richten sie replicafür die aktuelle Maschine ein. Die Datenbankreplikation sorgt für die Verteilung von Daten von primaryMaschine zu replicaMaschine. Sie navigieren alle Leseabfragen (Query ( Q) in CQRS) zu den Replikaten - jeder replicakann jede Leseanforderung bedienen, Sie navigieren alle Schreibabfragen (Command ( C) in CQRS) zu den primary. Die Replikation kann geringfügig verzögert sein, aber je nach Anwendungsfall ist dies in Ordnung.

Die meisten mittelgroßen Startups, die täglich einige hunderttausend Anfragen bearbeiten, können mit der Einrichtung eines Primärreplikats überleben, sofern sie regelmäßig ältere Daten archivieren.

Wenn Sie jetzt auf zwei weitere Städte skalieren, sehen Sie, dass Sie primarynicht alle writeAnfragen bearbeiten können . Viele writeAnfragen haben Latenz. Darüber hinaus wirkt sich die Verzögerung zwischen primaryund replicamanchmal auch auf Kunden und Fahrer aus. Wenn die Reise endet, zahlt der Kunde den Fahrer erfolgreich, aber der Fahrer kann die Zahlung nicht sehen, da die Aktivität des Kunden eine writeAnfrage ist, die an die geht primary, während die Aktivität des Fahrers eine readAnfrage ist das geht zu einer der Repliken. Ihr Gesamtsystem ist so langsam, dass der Fahrer die Zahlung mindestens eine halbe Minute lang nicht sehen kann - frustrierend für Fahrer und Kunden. Wie lösen Sie es?

Muster 4 - Multi-Primärreplikation

Sie haben mit der primary-replicaKonfiguration sehr gut skaliert , aber jetzt benötigen Sie mehr Schreibleistung. Möglicherweise sind Sie bereit, bei der readAnforderungsleistung ein wenig Kompromisse einzugehen. Warum nicht die Schreibanforderung auch an a verteilen replica?

In einer multi-primaryKonfiguration können alle Maschinen als primary& arbeiten replica. Sie können sich vorstellen, multi-primarywie ein Kreis von Maschinen sagt A->B->C->D->A. Bkann Daten replizieren von A, Ckann Daten von replizieren , kann Daten von replizieren von B, Dkann Daten von replizieren von . Sie können Daten auf jeden Knoten schreiben, während Sie Daten lesen, und die Abfrage an alle Knoten senden, wer auch immer antwortet, gibt dies zurück. Alle Knoten haben dasselbe Datenbankschema, denselben Satz von Tabellen, denselben Index usw. Sie müssen also sicherstellen, dass es keine Kollision zwischen Knoten in derselben Tabelle gibt. Andernfalls würden während des Broadcasts mehrere Knoten unterschiedliche Daten für denselben zurückgeben .CADidid

Im Allgemeinen ist es besser, UUIDoder GUIDfür ID zu verwenden. Ein weiterer Nachteil dieser Technik besteht darin, dass readAbfragen möglicherweise ineffizient sind, da sie das Senden von Abfragen und das Erhalten des richtigen Ergebnisses umfassen.

Jetzt skalieren Sie auf 5 weitere Städte und Ihr System hat wieder Schmerzen. Es wird erwartet, dass Sie ungefähr 50 Anfragen pro Sekunde bearbeiten. Sie müssen dringend eine große Anzahl gleichzeitiger Anfragen bearbeiten. Wie erreichen Sie das?

Muster 5 - Partitionierung:

Sie wissen, dass Ihre locationDatenbank etwas ist, das stark writeund readverkehrsreich wird. Wahrscheinlich ist das write:readVerhältnis 7:3. Dies setzt die vorhandenen Datenbanken stark unter Druck. Die locationTabellen enthalten einige Primärdaten wie longitude, latitude, timestamp, driver id, trip idetc. Es hat keine viel mit Benutzern Reisen, Benutzerdaten, Zahlungsdaten usw. Was die Trennung der zu tun locationTabellen in einem separaten Datenbank - Schema? Was ist mit dem Speichern dieser Datenbank auf separaten Computern mit der richtigen primary-replicaoder multi-primaryKonfiguration?

Dies wird als Partitionierung von Daten nach Funktionen bezeichnet. Unterschiedliche Datenbanken können Daten hosten, die nach unterschiedlichen Funktionen kategorisiert sind. Bei Bedarf kann das Ergebnis in der Back-End-Schicht zusammengefasst werden. Mit dieser Technik können Sie sich darauf konzentrieren, die Funktionen gut zu skalieren, die hohe read/writeAnforderungen erfordern . Obwohl das Back-End oder die Anwendungsschicht die Verantwortung übernehmen muss, die Ergebnisse bei Bedarf zusammenzuführen, was wahrscheinlich zu weiteren Codeänderungen führt.

Stellen Sie sich nun vor, Sie haben Ihr Geschäft auf insgesamt 20 Städte in Ihrem Land ausgeweitet und planen, bald nach Australien zu expandieren. Ihre steigende Nachfrage nach Apps erfordert eine schnellere und schnellere Reaktion. Keine der oben genannten Methoden kann Ihnen jetzt bis zum Äußersten helfen. Sie müssen Ihr System so skalieren, dass Sie bei einer Expansion in andere Länder / Regionen nicht immer häufige technische oder architektonische Änderungen vornehmen müssen. Wie machst du das?

Muster 6 - Horizontale Skalierung:

Sie googeln viel, lesen viel darüber, wie andere Unternehmen das Problem gelöst haben - und kommen zu dem Schluss, dass Sie horizontal skalieren müssen. Sie weisen beispielsweise 50 Maschinen zu - alle haben dasselbe Datenbankschema, das wiederum denselben Satz von Tabellen enthält. Alle Maschinen enthalten nur einen Teil der Daten.

Da alle Datenbanken denselben Tabellensatz enthalten, können Sie das System so gestalten, dass die Datenlokalität vorhanden ist, d. H. Alle zugehörigen Daten landen auf demselben Computer. Jeder Computer kann über eigene Replikate verfügen. Replikate können zur Fehlerbehebung verwendet werden. Jede der Datenbanken wird aufgerufen shard. Eine physische Maschine kann eine oder mehrere haben shards- es liegt an Ihrem Design, wie Sie es möchten. Sie müssen sich so entscheiden sharding key, dass sich eine einzelne sharding keyimmer auf dieselbe Maschine bezieht. Sie können sich also viele Computer vorstellen, die alle verwandte Daten in demselben Satz von Tabellen, read/writeAnforderungen für dieselbe Zeile oder denselben Satz von Ressourcenland in demselben Datenbankcomputer enthalten.

Sharding ist im Allgemeinen schwierig - zumindest sagen Ingenieure verschiedener Unternehmen dies. Aber wenn Sie Millionen oder Milliarden von Anfragen bearbeiten, müssen Sie eine so schwierige Entscheidung treffen.

Ich werde shardingin meinem nächsten Beitrag ausführlicher darauf eingehen, um meine Versuchung zurückzuhalten, in diesem Beitrag mehr zu besprechen.

Jetzt, da Sie Sharding installiert haben, sind Sie sicher, dass Sie auf viele Länder skalieren können. Ihr Geschäft ist so stark gewachsen, dass Investoren Sie dazu drängen, das Geschäft über Kontinente hinweg zu skalieren. Hier sehen Sie wieder ein Problem. Wieder API-Latenz. Ihr Service wird in den USA gehostet und Menschen aus Vietnam haben Schwierigkeiten, Fahrten zu buchen. Warum? Was machst du dagegen?

Muster 7 - Rechenzentrumsweise Partition:

Ihr Geschäft wächst in Amerika, Südasien und in wenigen Ländern Europas. Sie tätigen täglich Millionen von Buchungen, wobei Milliarden von Anfragen auf Ihren Server gelangen. Herzlichen Glückwunsch - dies ist ein Höhepunkt für Ihr Unternehmen.

Da Anfragen von der App über Hunderte oder Tausende von Servern im Internet über Kontinente übertragen werden müssen, entsteht die Latenz. Was ist mit der Verteilung des Datenverkehrs auf Rechenzentren? Sie können ein Rechenzentrum in Singapur einrichten, das alle Anfragen aus Südasien bearbeitet, ein Rechenzentrum in Deutschland kann alle Anfragen aus europäischen Ländern bearbeiten und ein kalifornisches Rechenzentrum kann alle Anfragen aus den USA bearbeiten.

Außerdem aktivieren Sie die datenübergreifende Replikation, die die Notfallwiederherstellung unterstützt. Wenn also das kalifornische Rechenzentrum eine Replikation zum Rechenzentrum in Singapur durchführt und alle Fälle in den USA aufgrund von Stromproblemen oder Naturkatastrophen abstürzen, können alle USA-Anfragen auf das Rechenzentrum in Singapur zurückgreifen und so weiter.

Diese Skalierungstechnik ist nützlich, wenn Sie Millionen von Kunden in verschiedenen Ländern bedienen müssen und keinen Datenverlust ausgleichen können. Sie müssen immer die Verfügbarkeit des Systems aufrechterhalten.

Dies sind einige allgemeine Schritt-für-Schritt-Techniken für die Datenbankskalierung. Obwohl die meisten Ingenieure nicht genügend Chancen haben, diese Techniken zu implementieren, ist es insgesamt besser, sich ein umfassenderes Bild über ein solches System zu machen, das Ihnen in Zukunft möglicherweise dabei helfen wird, ein besseres System- und Architekturdesign zu entwickeln.

In meinen nächsten Artikeln werde ich versuchen, einige der Konzepte im Detail zu diskutieren. Bitte geben Sie gegebenenfalls ein entsprechendes Feedback zu diesem Beitrag.

Der Artikel wurde ursprünglich auf dem Medium Account des Autors veröffentlicht: //medium.com/@kousiknath/understanding-database-scaling-patterns-ac24e5223522