Warum könnte eine halbsynchrone Replikation notwendig sein?

Hallo zusammen. Hier ist Wladislaw Rodin. Momentan unterrichte ich auf dem Portal OTUS Kurse, die sich mit Softwarearchitektur und Hochlast-Softwarearchitektur beschäftigen. In der Vorbereitungsphase für den Start eines neuen Kurses , wo ein erfahrener Spezialist auf diesem Gebiet Ihnen erklärt, wie Sie handeln sollten, damit der Server nicht mehr abstürzt. habe ich beschlossen, ein kleines eigenes Material zu schreiben, das ich mit Ihnen teilen möchte.

Warum könnte eine halbsynchrone Replikation notwendig sein?

Einführung

Da auf einer HDD nur etwa 400-700 Operationen pro Sekunde ausgeführt werden können (was im Vergleich zu typischen rps, die auf ein hochbelastetes System entfallen, unvorstellbar ist), ist eine klassische Datenbank ein Engpass in der Architektur. Daher ist es notwendig, besondere Aufmerksamkeit den Skalierungsmustern dieses Speichers zu widmen.

Derzeit gibt es 2 Skalierungsmuster für die Datenbank: Replikation und Sharding. Sharding ermöglicht es, die Schreiboperation zu skalieren und somit die rps beim Schreiben, die auf einen Server Ihres Clusters entfallen, zu reduzieren. Die Replikation ermöglicht dasselbe, jedoch für Leseoperationen. Genau diesem Muster ist dieser Artikel gewidmet.

Replikation

Wenn man sich die Replikation ganz allgemein ansieht, ist es eine einfache Sache: Sie hatten einen Server, auf dem die Daten lagen, und dann konnte dieser Server die Leseanforderungen dieser Daten nicht mehr bewältigen. Sie fügen ein paar Server hinzu, synchronisieren die Daten auf allen Servern, und der Benutzer kann von jedem Server Ihres Clusters lesen.

Trotz der scheinbaren Einfachheit gibt es mehrere Klassifizierungsmöglichkeiten für verschiedene Implementierungen dieses Schemas:

  • Nach Rollen im Cluster (Master-Master oder Master-Slave)
  • Nach übermittelten Objekten (zeilenbasiert, statements-basiert oder gemischt)
  • Nach dem Mechanismus zur Synchronisation der Knoten

Heute werden wir uns genau mit dem 3. Punkt beschäftigen.

Wie der Commit einer Transaktion abläuft

Dieses Thema gehört nicht direkt zur Replikation, darüber könnte ein separater Artikel geschrieben werden, aber da das Verständnis des Commit-Mechanismus für das weitere Lesen unerlässlich ist, erlaube ich mir, die grundlegendsten Dinge in Erinnerung zu rufen. Der Commit einer Transaktion erfolgt in 3 Phasen:

  1. Aufzeichnung der Transaktion im Datenbankprotokoll.
  2. Anwendung der Transaktion im Datenbank-Engine.
  3. Rücksendung der Bestätigung an den Kunden über die erfolgreiche Anwendung der Transaktion.

In verschiedenen Datenbanken können in diesem Algorithmus Nuancen auftreten: Zum Beispiel gibt es im InnoDB-Engine von MySQL 2 Protokolle: eines für die Replikation (binary log) und ein anderes zur Aufrechterhaltung von ACID (undo/redolog), während PostgreSQL ein Protokoll hat, das beide Funktionen erfüllt (write ahead log = WAL). Aber oben wurde genau das allgemeine Konzept vorgestellt, das solche Nuancen unberücksichtigt lässt.

Synchronisierte (sync) Replikation

Lassen Sie uns dem Commit-Algorithmus der Transaktion Logik zur Replikation der erhaltenen Änderungen hinzufügen:

  1. Aufzeichnung der Transaktion im Datenbankprotokoll.
  2. Anwendung der Transaktion im Datenbank-Engine.
  3. Daten an alle Replikate senden.
  4. Bestätigung von allen Replikaten über die Durchführung der Transaktion erhalten.
  5. Rücksendung der Bestätigung an den Kunden über die erfolgreiche Anwendung der Transaktion.

Bei diesem Ansatz ergeben sich einige Nachteile:

  • der Client wartet, bis die Änderungen auf allen Replikaten angewendet werden.
  • Mit zunehmender Anzahl der Nodes im Cluster verringern wir die Wahrscheinlichkeit, dass die Schreiboperation erfolgreich abgeschlossen wird.

Wenn der erste Punkt mehr oder weniger klar ist, sollte der zweite Punkt erläutert werden. Wenn bei synchroner Replikation keine Antwort von mindestens einem Node vorliegt, rollen wir die Transaktion zurück. So erhöht man, indem man die Anzahl der Nodes im Cluster vergrößert, die Wahrscheinlichkeit, dass die Schreiboperation fehlschlägt.

Können wir nur auf eine bestimmte Anzahl von Nodes, zum Beispiel 51% (Quorum), eine Bestätigung erwarten? Ja, das können wir, jedoch erfordert es im klassischen Szenario die Bestätigung von allen Nodes, da wir nur so die vollständige Konsistenz der Daten im Cluster gewährleisten können, was unbestreitbar ein Vorteil dieser Replikationsart ist.

Asynchrone (async) Replikation

Lassen Sie uns den vorherigen Algorithmus abwandeln. Wir werden die Daten an die Replikate "irgendwann später" senden, und "irgendwann später" werden die Änderungen auf den Replikaten angewendet:

  1. Aufzeichnung der Transaktion im Datenbankprotokoll.
  2. Anwendung der Transaktion im Datenbank-Engine.
  3. Rücksendung der Bestätigung an den Kunden über die erfolgreiche Anwendung der Transaktion.
  4. Daten an die Replikate senden und Änderungen anwenden.

Dieser Ansatz führt dazu, dass der Cluster schnell arbeitet, da wir den Client nicht warten lassen, bis die Daten zu den Replikaten gelangen und auch noch festgeschrieben werden.

Aber die Bedingung, Daten "irgendwann später" auf die Replikate zu übertragen, kann dazu führen, dass Transaktionen verloren gehen, insbesondere bestätigte Transaktionen für den Benutzer, denn wenn die Daten nicht rechtzeitig repliziert wurden, wird die Bestätigung an den Client über den erfolgreichen Abschluss der Operation gesendet, und wenn das HDD des Nodes, an den die Änderungen gesendet wurden, ausfällt, verlieren wir die Transaktion, was zu sehr unangenehmen Folgen führen kann.

Halbsynchrone (semisync) Replikation

Endlich haben wir die semi-synchrone Replikation erreicht. Diese Art der Replikation ist nicht sehr bekannt und nicht weit verbreitet, bietet jedoch ein gewisses Interesse, da sie die Vorteile sowohl der synchronen als auch der asynchronen Replikation kombinieren kann.

Lass uns die beiden vorherigen Ansätze kombinieren. Wir werden den Client nicht lange warten lassen, verlangen jedoch, dass die Daten repliziert werden:

  1. Aufzeichnung der Transaktion im Datenbankprotokoll.
  2. Anwendung der Transaktion im Datenbank-Engine.
  3. Daten an die Replikate senden.
  4. Erhalt einer Bestätigung von der Replik über den Erhalt der Änderungen (diese werden "irgendwann später" angewendet).
  5. Rücksendung der Bestätigung an den Kunden über die erfolgreiche Anwendung der Transaktion.

Beachte, dass bei diesem Algorithmus der Verlust einer Transaktion nur dann auftritt, wenn sowohl der Knoten, der die Änderungen akzeptiert, als auch der Replikationsknoten ausfallen. Die Wahrscheinlichkeit eines solchen Ausfalls wird als gering eingeschätzt, und diese Risiken werden akzeptiert.

Bei diesem Ansatz besteht jedoch das Risiko von Phantomlesen. Stellen wir uns folgendes Szenario vor: In Schritt 4 haben wir von keiner Replik eine Bestätigung erhalten. Wir müssen diese Transaktion zurücksetzen, ohne dem Client eine Bestätigung zurückzugeben. Da die Daten in Schritt 2 angewendet wurden, entsteht zwischen dem Ende von Schritt 2 und dem Zurücksetzen der Transaktion ein Zeitfenster, in dem parallele Transaktionen die Änderungen sehen könnten, die in der Datenbank nicht vorhanden sein sollten.

Lose-less semi-synchrone Replikation

Wenn man ein wenig nachdenkt, kann man durch einfaches Vertauschen der Schritte im Algorithmus das Problem der Phantomlesungen in diesem Szenario beheben:

  1. Aufzeichnung der Transaktion im Datenbankprotokoll.
  2. Daten an die Replik senden.
  3. Erhalt einer Bestätigung von der Replik über den Erhalt der Änderungen (diese werden "irgendwann später" angewendet).
  4. Anwendung der Transaktion im Datenbank-Engine.
  5. Rücksendung der Bestätigung an den Kunden über die erfolgreiche Anwendung der Transaktion.

Jetzt bestätigen wir die Änderungen nur, wenn sie repliziert wurden.

Ausgabe

Wie immer gibt es keine perfekten Lösungen, sondern eine Reihe von Lösungen, von denen jede ihre eigenen Vor- und Nachteile hat und für die Lösung verschiedener Klassen von Aufgaben geeignet ist. Dies gilt auch für die Wahl des Mechanismus zur Synchronisierung der Daten der replizierten Datenbank. Das Set an Vorteilen, das die semi-synchrone Replikation bietet, ist ziemlich solide und interessant genug, um als bemerkenswert eingestuft zu werden, trotz ihrer geringen Verbreitung.

Das wäre alles. Bis zum nächsten Mal bei Kurs!

Quelle: habr.com

60GB SSD 8Gb DDR4