Warum benötigen Sie möglicherweise eine halbsynchrone Replikation?

Hallo alle zusammen. In Kontakt Vladislav Rodin. Ich unterrichte derzeit Kurse über Softwarearchitektur und Hochlast-Softwarearchitektur auf dem OTUS-Portal. Im Vorgriff auf den Start eines neuen Streams des Kurses „Architekt hoher Lasten“ habe ich beschlossen, ein kleines Autorenmaterial zu schreiben, das ich mit Ihnen teilen möchte.




Einführung


Aufgrund der Tatsache, dass auf der Festplatte nur etwa 400 bis 700 Vorgänge pro Sekunde ausgeführt werden können (was mit typischen RPS auf einem stark ausgelasteten System nicht zu vergleichen ist), ist die klassische Festplattendatenbank ein enger Architekturbereich. Daher sollte den Skalierungsmustern dieses Repositorys besondere Aufmerksamkeit gewidmet werden.

Im Moment gibt es zwei Muster der Basisskalierung: Replikation und Sharding. Durch Sharding können Sie den Schreibvorgang skalieren und dadurch die RPS für die Aufzeichnung pro Server in Ihrem Cluster reduzieren. Mit der Replikation können Sie dasselbe tun, jedoch mit Lesevorgängen. Dieser Artikel ist genau diesem Muster gewidmet.

Reproduzieren


Wenn Sie sich die Replikation auf höchster Ebene ansehen, ist dies eine einfache Sache: Sie hatten einen Server, die Daten befanden sich darauf, und dann hat dieser Server die Last des Lesens dieser Daten nicht mehr bewältigt. Sie fügen ein paar weitere Server hinzu, synchronisieren Daten auf allen Servern und der Benutzer kann von jedem Server in Ihrem Cluster lesen.

Trotz der offensichtlichen Einfachheit gibt es verschiedene Klassifizierungsoptionen für verschiedene Implementierungen dieses Schemas:

  • Nach Rollen im Cluster (Master-Master oder Master-Slave)
  • Durch weitergeleitete Objekte (zeilenbasiert, anweisungsbasiert oder gemischt)
  • Entsprechend dem Knotensynchronisationsmechanismus

Heute werden wir uns mit dem 3. Punkt befassen.

Wie wird die Transaktion festgeschrieben?


Dieses Thema steht nicht in direktem Zusammenhang mit der Replikation. Es kann jedoch ein separater Artikel darüber geschrieben werden. Da jedoch ohne weiteres Verständnis des Transaktions-Commit-Mechanismus eine weitere Lektüre nutzlos ist, möchte ich Sie an die grundlegendsten Dinge erinnern. Eine Transaktion wird in 3 Schritten festgeschrieben:

  1. Schreiben einer Transaktion in das Datenbankprotokoll.
  2. Anwendung einer Transaktion in einem Datenbankmodul.
  3. Senden Sie dem Kunden eine Bestätigung über die erfolgreiche Anwendung der Transaktion zurück.

In diesem Algorithmus können in verschiedenen Datenbanken Nuancen auftreten: In der InnoDB-Engine der MySQL-Datenbank gibt es beispielsweise zwei Protokolle: eines für die Replikation (binäres Protokoll) und das andere für die Verwaltung von ACID (Undo / Redo-Protokoll), während in PostgreSQL ein Protokoll ausgeführt wird beide Funktionen (Write Ahead Log = WAL). Aber oben ist es genau das allgemeine Konzept, das es erlaubt, solche Nuancen zu ignorieren.

Synchrone (Synchronisierungs-) Replikation


Fügen wir die Logik zum Replizieren der empfangenen Änderungen zum Transaktions-Commit-Algorithmus hinzu:

  1. Schreiben einer Transaktion in das Datenbankprotokoll.
  2. Anwendung einer Transaktion in einem Datenbankmodul.
  3. Senden von Daten an alle Replikate.
  4. Erhalten Sie von allen Replikaten eine Bestätigung über die Transaktion auf ihnen.
  5. Senden Sie dem Kunden eine Bestätigung über die erfolgreiche Anwendung der Transaktion zurück.

Mit diesem Ansatz haben wir eine Reihe von Nachteilen:

  • Der Client wartet darauf, dass Änderungen auf alle Replikate angewendet werden.
  • Wenn die Anzahl der Knoten im Cluster zunimmt, verringern wir die Wahrscheinlichkeit, dass der Schreibvorgang erfolgreich ist.

Wenn mit dem 1. Absatz alles mehr oder weniger klar ist, sollten die Gründe für den 2. Absatz geklärt werden. Wenn wir während der synchronen Replikation keine Antwort von mindestens einem Knoten erhalten, wird die Transaktion zurückgesetzt. Wenn Sie also die Anzahl der Knoten im Cluster erhöhen, erhöhen Sie die Wahrscheinlichkeit, dass der Schreibvorgang fehlschlägt.

Können wir nur von einem bestimmten Bruchteil der Knoten auf eine Bestätigung warten, beispielsweise von 51% (Quorum)? Ja, das können wir, aber in der klassischen Version ist eine Bestätigung von allen Knoten erforderlich, da wir auf diese Weise die vollständige Konsistenz der Daten im Cluster sicherstellen können, was zweifellos ein Vorteil dieser Art der Replikation ist.

Asynchrone Replikation


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

  1. Schreiben einer Transaktion in das Datenbankprotokoll.
  2. Anwendung einer Transaktion in einem Datenbankmodul.
  3. Senden Sie dem Kunden eine Bestätigung über die erfolgreiche Anwendung der Transaktion zurück.
  4. Senden von Daten an Replikate und Anwenden von Änderungen auf diese.

Dieser Ansatz führt dazu, dass der Cluster schnell ist, da der Client nicht darauf wartet, dass die Daten die Replikate erreichen und sogar kommuniziert werden.

Die Bedingung, Daten "irgendwann später" in Replikate zu löschen, kann jedoch zum Verlust der Transaktion und zum Verlust der dem Benutzer bestätigten Transaktion führen. Wenn die Daten keine Zeit zum Replizieren hatten, wurde dem Client eine Bestätigung über den Erfolg des Vorgangs gesendet, und der Knoten, an dem die Änderungen eingegangen sind, flog HDD, wir verlieren die Transaktion, was zu sehr unangenehmen Konsequenzen führen kann.

Semisync-Replikation


Schließlich kamen wir zur halbsynchronen Replikation. Diese Art der Replikation ist nicht sehr bekannt und nicht sehr verbreitet, aber von erheblichem Interesse, da sie die Vorteile sowohl der synchronen als auch der asynchronen Replikation kombinieren kann.

Versuchen wir, die beiden vorherigen Ansätze zu kombinieren. Wir werden den Client nicht lange behalten, aber wir verlangen, dass die Daten repliziert werden:

  1. Schreiben einer Transaktion in das Datenbankprotokoll.
  2. Anwendung einer Transaktion in einem Datenbankmodul.
  3. Senden von Daten an Replikate.
  4. Erhalten einer Bestätigung vom Replikat über den Empfang von Änderungen (diese werden "einige Zeit später" angewendet).
  5. Senden Sie dem Kunden eine Bestätigung über die erfolgreiche Anwendung der Transaktion zurück.

Beachten Sie, dass bei diesem Algorithmus ein Transaktionsverlust nur auftritt, wenn der Knoten die Änderungen und die Replikatknoten akzeptiert. Die Wahrscheinlichkeit einer solchen Fehlfunktion wird als gering angesehen, und diese Risiken werden akzeptiert.

Mit diesem Ansatz ist jedoch das Risiko von Phantomablesungen möglich. Stellen Sie sich das folgende Szenario vor: In Schritt 4 haben wir keine Bestätigung von einem Replikat erhalten. Wir müssen diese Transaktion zurücksetzen und die Bestätigung nicht an den Kunden zurücksenden. Da die Daten in Schritt 2 angewendet wurden, besteht zwischen dem Ende von Schritt 2 und dem Transaktions-Rollback eine Zeitlücke, in der parallele Transaktionen die Änderungen sehen können, die nicht in der Datenbank enthalten sein sollten.

Verlustfreie semisynchrone Replikation


Wenn Sie ein wenig nachdenken, können Sie die Schritte des Algorithmus nur an einigen Stellen ändern, um das Problem der Phantomablesungen in diesem Szenario zu beheben:

  1. Schreiben einer Transaktion in das Datenbankprotokoll.
  2. Senden von Replikatdaten.
  3. Erhalten einer Bestätigung vom Replikat über den Empfang von Änderungen (diese werden "einige Zeit später" angewendet).
  4. Anwendung einer Transaktion in einem Datenbankmodul.
  5. Senden Sie dem Kunden eine Bestätigung über die erfolgreiche Anwendung der Transaktion zurück.

Jetzt übernehmen wir Änderungen nur, wenn sie repliziert werden.

Fazit


Wie immer gibt es keine perfekten Lösungen, es gibt eine Reihe von Lösungen, von denen jede ihre eigenen Vor- und Nachteile hat und zur Lösung verschiedener Problemklassen geeignet ist. Dies gilt auch für die Auswahl eines Mechanismus zum Synchronisieren der Daten einer replizierten Datenbank. Die Vorteile der halbsynchronen Replikation sind solide und interessant genug, um trotz ihrer geringen Verbreitung als beachtlich angesehen zu werden.

Das ist alles. Wir sehen uns auf dem Kurs !

All Articles