Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Ein Leitfaden zum Verständnis von Datenbankskalierungsmustern

Es gibt viele Artikel online, die Datenbank-Skalierbarkeitsmuster beschreiben, aber es handelt sich meist um verstreute Artikel – nur Techniken, die willkürlich ohne viel Kontext definiert werden. Ich finde, dass sie nicht Schritt für Schritt definiert sind und nicht diskutieren, wann welche Skalierungsoption zu wählen ist, welche Skalierungsoptionen in der Praxis machbar sind und warum.

Daher plane ich, einige der Techniken in zukünftigen Artikeln im Detail zu diskutieren. Zu Beginn finde ich es besser, wenn ich Schritt-für-Schritt-Techniken mit einem gewissen Kontext auf meine eigene Weise bespreche. Dieser Artikel ist ein High-Level-Artikel – ich werde Skalierungstechniken hier nicht im Detail diskutieren, aber einen Überblick geben. Fangen wir also an.

Eine Fallstudie

Angenommen, Sie haben ein Startup aufgebaut, das günstige Mitfahrgelegenheiten anbietet. Wenn Sie anfangen, zielen Sie zunächst auf eine Stadt ab und haben nach Ihrer ersten Anzeige kaum Dutzende von Kunden.

Sie speichern alle Kunden, Reisen, Standorte, Buchungsdaten und den Verlauf der Kundenreisen in derselben Datenbank oder höchstwahrscheinlich auf einem einzigen physischen Computer. Es gibt kein ausgefallenes Caching oder eine große Datenpipeline, 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 1 Fahrt in 5 Minuten bucht.

Aber im Laufe der Zeit melden sich immer mehr Leute in Ihrem System an, da Sie der billigste Dienst auf dem Markt sind und dank Ihrer Werbung und Werbung. Sie beginnen mit der Buchung, sagen wir, 10 Buchungen pro Minute, und langsam steigt die Zahl auf 20, 30 Buchungen pro Minute.

Zu diesem Zeitpunkt stellen Sie fest, dass das System schlecht funktioniert:Die API-Latenz hat sich stark erhöht, und einige Transaktionen blockieren oder verhungern und schlagen schließlich fehl. 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 von Abfrageoptimierung und Verbindungspool:

Die erste Lösung, die mir in den Sinn kommt, ist, dass der Cache häufig nicht dynamische Daten wie Buchungshistorie, Zahlungshistorie, Benutzerprofile usw. verwendet. Aber nach diesem Zwischenspeichern auf Anwendungsebene können Sie das Latenzproblem von APIs nicht lösen, die dynamische Daten wie den aktuellen Fahrerstandort oder die nächstgelegenen Taxis für einen bestimmten Kunden oder aktuelle Fahrtkosten zu einem bestimmten Zeitpunkt nach Beginn der Fahrt offenlegen.

Sie stellen fest, dass Ihre Datenbank wahrscheinlich stark normalisiert ist, also führen Sie einige redundante Spalten ein (diese Spalten erscheinen häufig in WHERE oder JOIN ON -Klausel in Abfragen) in häufig verwendeten Tabellen zum Zweck der Denormalisierung. Dadurch werden Join-Abfragen reduziert, eine große Abfrage in mehrere kleinere Abfragen aufgeteilt und deren Ergebnisse in der Anwendungsschicht addiert.

Eine weitere parallele Optimierung, die Sie vornehmen können, ist die Optimierung 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 Erstellen einer Netzwerkverbindung ist kostspielig, da es eine gewisse Hin- und Herkommunikation zwischen Client und Server erfordert. Pooling-Verbindungen können Ihnen dabei helfen, die Anzahl der Verbindungen zu 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 Connection Pooling im Detail erläutern kann.

Sie messen die Latenz Ihrer APIs und finden wahrscheinlich 20–50 % oder mehr reduzierte Latenz. Das ist zum jetzigen Zeitpunkt eine gute Optimierung.

Sie haben Ihr Geschäft jetzt auf eine weitere Stadt skaliert, mehr Kunden melden sich an, Sie beginnen langsam, 80–100 Buchungen pro Minute zu tätigen. Ihr System ist nicht in der Lage, mit dieser Größenordnung umzugehen. Wieder sehen Sie, dass sich die API-Latenz erhöht hat, die Datenbankschicht aufgegeben hat, aber dieses Mal bringt Ihnen keine Abfrageoptimierung einen signifikanten Leistungsgewinn. Sie überprüfen die Systemmetrik und stellen fest, dass der Festplattenspeicher fast voll ist, die CPU zu 80 % der Zeit ausgelastet ist und der Arbeitsspeicher sehr schnell voll ist.

Muster 2 – Vertikale Skalierung oder Skalierung:

Nachdem Sie alle Systemmetriken untersucht haben, wissen Sie, dass es keine andere einfache Lösung gibt, als die Hardware des Systems zu aktualisieren. Sie erweitern Ihre RAM-Größe um das 2-fache, den Festplattenspeicher um das 3-fache oder mehr. Dies wird als vertikales Skalieren oder Hochskalieren Ihres Systems bezeichnet. Sie informieren Ihr Infrastrukturteam oder Entwicklerteam oder Rechenzentrumsagenten von Drittanbietern, um Ihren Computer zu aktualisieren.

Aber wie richtet man die Maschine für die vertikale Skalierung ein?

Sie weisen eine größere Maschine zu. Ein Ansatz besteht darin, Daten nicht manuell von der alten Maschine zu migrieren, sondern die neue Maschine als replica festzulegen an die vorhandene Maschine (primary ) – Erstellen Sie eine temporäre primary replica Aufbau. Lassen Sie die Replikation auf natürliche Weise erfolgen. Sobald die Replikation abgeschlossen ist, stufen Sie den neuen Computer zum primären Computer hoch und schalten Sie den älteren Computer offline. Da von der größeren Maschine erwartet wird, dass sie alle Anfragen bedient, werden alle Lese-/Schreibvorgänge auf dieser Maschine stattfinden.

Cool. Ihr System läuft wieder mit gesteigerter Leistung.

Ihr Geschäft läuft sehr gut und Sie beschließen, auf 3 weitere Städte zu skalieren – Sie sind jetzt in insgesamt 5 Städten tätig. Der Verkehr ist dreimal so hoch wie früher, es wird mit etwa 300 Buchungen pro Minute gerechnet. Bevor Sie diese Zielbuchung überhaupt erreichen, geraten Sie erneut in die Leistungskrise, die Indexgröße der Datenbank nimmt im Speicher stark zu, sie muss ständig gewartet werden, das Scannen von Tabellen mit Index wird langsamer als je zuvor. Sie kalkulieren die Kosten für eine weitere Skalierung der Maschine, sind aber von den Kosten nicht überzeugt. Was machst du jetzt?

Muster 3 – Trennung der Verantwortung für Befehlsabfragen (CQRS):

Sie stellen fest, dass die große Maschine nicht in der Lage ist, alle read/write zu verarbeiten Anfragen. Außerdem benötigt jedes Unternehmen in den meisten Fällen Transaktionsfähigkeiten beim write aber nicht auf read Operationen. Sie sind auch mit ein wenig inkonsistentem oder verzögertem read zufrieden Operationen und Ihr Unternehmen hat auch kein Problem damit. Sie sehen eine Möglichkeit, bei der es eine gute Option sein könnte, das read zu trennen &write Operationen physische Maschine weise. Es wird Spielraum für einzelne Maschinen schaffen, um mehr read/write zu handhaben Operationen.

Du nimmst jetzt zwei weitere große Maschinen &stellst sie als replica auf zur aktuellen Maschine. Die Datenbankreplikation kümmert sich um die Verteilung von Daten von primary Maschine zum replica Maschinen. Sie navigieren durch alle Leseabfragen (Abfrage (Q ) in CQRS ) zu den Replikaten – jeder replica kann jede Leseanfrage bedienen, navigiert man alle Schreibanfragen (Befehl (C ) in CQRS ) zum primary . Bei der Replikation kann es zu kleinen Verzögerungen kommen, aber je nach Ihrem geschäftlichen Anwendungsfall ist das in Ordnung.

Die meisten mittelständischen Startups, die täglich einige hunderttausend Anfragen bedienen, können mit der Einrichtung einer primären Replik überleben, vorausgesetzt, sie archivieren regelmäßig ältere Daten.

Wenn Sie jetzt auf 2 weitere Städte skalieren, sehen Sie, dass Ihre primary ist nicht in der Lage, alle write zu verarbeiten Anfragen. Viele write Anfragen haben Latenz. Außerdem ist die Verzögerung zwischen primary &replica wirkt sich manchmal auf Kunden und Fahrer aus, z. B. – wenn die Fahrt endet, bezahlt der Kunde den Fahrer erfolgreich, aber der Fahrer kann die Zahlung nicht sehen, da die Aktivität des Kunden ein write ist Anfrage, die an primary geht , während die Aktivität des Fahrers ein read ist Anfrage, die an eine der Repliken geht. 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 – Multiprimäre Replikation

Sie haben mit primary-replica wirklich gut skaliert Konfiguration, aber jetzt brauchen Sie mehr Schreibleistung. Vielleicht sind Sie bereit, bei read ein wenig Kompromisse einzugehen Leistung verlangen. Warum verteilen Sie die Schreibanfrage nicht an eine replica auch?

In einem multi-primary Konfiguration können alle Maschinen sowohl als primary arbeiten &replica . Sie können an multi-primary denken als Kreis von Maschinen sagen Sie A->B->C->D->A . B kann Daten von A replizieren , C kann Daten von B replizieren , D kann Daten von C replizieren , A kann Daten von D replizieren . Sie können Daten auf jeden Knoten schreiben, während Sie Daten lesen, können Sie die Abfrage an alle Knoten senden, wer auch immer antwortet, gibt das zurück. Alle Knoten haben das gleiche Datenbankschema, den gleichen Tabellensatz, den gleichen Index usw. Sie müssen also sicherstellen, dass es keine Kollisionen in id gibt über Knoten hinweg in derselben Tabelle, ansonsten würden mehrere Knoten während des Sendens unterschiedliche Daten für dieselbe id zurückgeben .

Im Allgemeinen ist es besser, UUID zu verwenden oder GUID für id. Ein weiterer Nachteil dieser Technik ist — read Abfragen könnten ineffizient sein, da es darum geht, Abfragen zu senden und das richtige Ergebnis zu erhalten – im Grunde ein Scatter-Gather-Ansatz.

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

Muster 5 – Partitionierung:

Sie kennen Ihren location Datenbank ist etwas, das write hoch wird &read Verkehr. Wahrscheinlich write:read Verhältnis ist 7:3 . Dies setzt die bestehenden Datenbanken stark unter Druck. Der location Tabellen enthalten wenige Primärdaten wie longitude , latitude , timestamp , driver id , trip id usw. Es hat nicht viel mit Benutzerfahrten, Benutzerdaten, Zahlungsdaten usw. zu tun. Was ist mit der Trennung des location Tabellen in einem separaten Datenbankschema? Wie wäre es, diese Datenbank auf separaten Computern mit dem richtigen primary-replica zu platzieren oder multi-primary Aufbau?

Dies wird Partitionieren von Daten nach Funktionalität genannt. Verschiedene Datenbanken können Daten hosten, die nach unterschiedlichen Funktionen kategorisiert sind, bei Bedarf kann das Ergebnis in der Back-End-Schicht aggregiert werden. Mit dieser Technik können Sie sich darauf konzentrieren, jene Funktionalitäten gut zu skalieren, die viel read/write erfordern Anfragen. Obwohl das Back-End oder die Anwendungsschicht die Verantwortung dafür ü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 der Erweiterung auf andere Länder/Regionen nicht immer häufige Konstruktions- oder Architekturä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 Tabellensatz enthält. Alle Maschinen halten nur einen Teil der Daten.

Da alle Datenbanken den gleichen Tabellensatz enthalten, können Sie das System so gestalten, dass die Lokalität der Daten vorhanden ist, d.h. alle zugehörigen Daten landen auf derselben Maschine. Jede Maschine kann ihre eigenen Repliken haben, Repliken können bei der Fehlerwiederherstellung verwendet werden. Jede der Datenbanken wird shard genannt . Eine physische Maschine kann einen oder mehrere shards haben – es liegt an Ihrem Design, wie Sie es möchten. Sie müssen sich für sharding key entscheiden so dass ein einzelner sharding key bezieht sich immer auf die gleiche Maschine. Sie können sich also viele Maschinen vorstellen, die alle zusammengehörige Daten in denselben Tabellen enthalten, read/write Anforderungen für die gleiche Zeile oder den gleichen Ressourcensatz landen auf der gleichen Datenbankmaschine.

Sharding ist im Allgemeinen schwierig – das sagen zumindest Ingenieure verschiedener Unternehmen. Aber wenn Sie Millionen oder Milliarden von Anfragen bearbeiten, müssen Sie solch schwierige Entscheidungen treffen.

Ich werde sharding besprechen ausführlicher in meinem nächsten Post, also halte ich meine Versuchung zurück, mehr in diesem Post zu diskutieren.

Da Sie nun Sharding eingerichtet haben, können Sie sicher sein, 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. Sie sehen hier wieder ein Problem. API-Latenz erneut. Ihr Service wird in den USA gehostet und Menschen aus Vietnam haben Schwierigkeiten, Fahrten zu buchen. Wieso den? Was tun Sie dagegen?

Muster 7 – Data Center Wise Partition:

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

Da aber Anfragen aus der App über Kontinente hinweg über Hunderte oder Tausende von Servern im Internet laufen 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 rechenzentrumsübergreifende Replikation, die die Notfallwiederherstellung unterstützt. Wenn also das kalifornische Rechenzentrum eine Replikation zum Rechenzentrum in Singapur durchführt, falls das kalifornische Rechenzentrum aufgrund von Stromproblemen oder Naturkatastrophen abstürzt, können alle Anfragen aus den USA 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 hinnehmen können. Sie müssen die Verfügbarkeit des Systems immer aufrechterhalten.

Dies sind einige allgemeine Schritt-für-Schritt-Techniken für die Datenbankskalierung. Obwohl die meisten Ingenieure nicht genug Gelegenheit haben, diese Techniken zu implementieren, ist es insgesamt besser, sich eine breitere Vorstellung von einem solchen System zu machen, was Ihnen in Zukunft helfen kann, ein besseres System- und Architekturdesign durchzuführen.

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

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