banner

Nachricht

Mar 07, 2023

Aufbau und Bereitstellung von MySQL Raft bei Meta

Bei Meta betreiben wir eine der größten MySQL-Implementierungen weltweit. Die Bereitstellung unterstützt den Social Graph zusammen mit vielen anderen Diensten wie Messaging, Anzeigen und Feed. In den letzten Jahren haben wir MySQL Raft implementiert, eine Raft-Konsens-Engine, die in MySQL integriert wurde, um eine replizierte Zustandsmaschine zu erstellen. Wir haben einen großen Teil unserer Bereitstellung auf MySQL Raft migriert und planen, die aktuellen halbsynchronen MySQL-Datenbanken vollständig damit zu ersetzen. Das Projekt hat der MySQL-Bereitstellung bei Meta erhebliche Vorteile gebracht, darunter höhere Zuverlässigkeit, nachweisbare Sicherheit, erhebliche Verbesserungen der Failover-Zeit und betriebliche Einfachheit – und das alles bei gleicher oder vergleichbarer Schreibleistung.

Um hohe Verfügbarkeit, Fehlertoleranz und skalierbare Lesevorgänge zu ermöglichen, ist der MySQL-Datenspeicher von Meta eine massiv fragmentierte, georeplizierte Bereitstellung mit Millionen von Shards, die Petabytes an Daten speichern. Der Einsatz umfasst Tausende von Maschinen, die in mehreren Regionen und Rechenzentren auf mehreren Kontinenten laufen.

Zuvor nutzte unsere Replikationslösung das halbsynchrone (semisync) MySQL-Replikationsprotokoll. Dabei handelte es sich um ein Nur-Datenpfad-Protokoll. Der MySQL-Primärserver würde eine halbsynchrone Replikation auf zwei Nur-Protokoll-Replikate (Logtailer) innerhalb der Primärregion, aber außerhalb der Fehlerdomäne des Primärservers verwenden. Diese beiden Logtailer würden als halbsynchroner ACKer fungieren (Ein ACK ist eine Bestätigung an den Primärserver, dass die Transaktion lokal geschrieben wurde). Dies würde es dem Datenpfad ermöglichen, Commits mit sehr geringer Latenz (unter einer Millisekunde) durchzuführen und eine hohe Verfügbarkeit/Haltbarkeit für die Schreibvorgänge bereitzustellen. Für eine breitere Verteilung in anderen Regionen wurde die reguläre MySQL-Primär-zu-Replikat-Replikation verwendet.

Die Vorgänge auf der Steuerungsebene (z. B. Hochstufungen, Failover und Mitgliedschaftsänderungen) liegen in der Verantwortung einer Reihe von Python-Daemons (im Folgenden als Automatisierung bezeichnet). Die Automatisierung würde die notwendige Orchestrierung durchführen, um einen neuen MySQL-Server an einem Failover-Standort als primären Server zu befördern. Die Automatisierung würde auch die vorherige Primärdatenbank und die verbleibenden Replikate darauf hinweisen, von der neuen Primärdatenbank zu replizieren. Mitgliedschaftsänderungsvorgänge würden durch eine andere Automatisierung namens MySQL Pool Scanner (MPS) orchestriert. Um ein neues Mitglied hinzuzufügen, würde MPS das neue Replikat auf den Primärserver verweisen und es dem Service Discovery Store hinzufügen. Ein Failover wäre ein komplexerer Vorgang, bei dem die Tailing-Threads der Logtailer (semisynchrone ACKer) heruntergefahren würden, um den zuvor toten Primärserver abzugrenzen.

Um die Sicherheit zu gewährleisten und Datenverluste während der komplexen Hochstufungs- und Failover-Vorgänge zu vermeiden, verwendeten mehrere Automatisierungs-Daemons und Skripts in der Vergangenheit Sperren, Orchestrierungsschritte, einen Fencing-Mechanismus und SMC, ein Service-Discovery-System. Es handelte sich um einen verteilten Aufbau, und es war schwierig, dies atomar zu bewerkstelligen. Die Automatisierung wurde im Laufe der Zeit komplexer und schwieriger zu warten, da immer mehr Eckfälle gepatcht werden mussten.

Wir haben uns für einen völlig anderen Ansatz entschieden. Wir haben MySQL verbessert und es zu einem wirklich verteilten System gemacht. Da wir erkannten, dass Vorgänge auf der Steuerungsebene wie Beförderungen und Mitgliedschaftsänderungen der Auslöser der meisten Probleme waren, wollten wir, dass die Vorgänge auf der Steuerungsebene und auf der Datenebene Teil desselben replizierten Protokolls sind. Hierzu haben wir das bekannte Konsensprotokoll Raft verwendet. Dies bedeutete auch, dass die Quelle der Wahrheit über Mitgliedschaft und Führung innerhalb des Servers (mysqld) verlagert wurde. Dies war der größte Einzelbeitrag der Einführung von Raft, da es eine nachweisbare Korrektheit (Sicherheitseigenschaft) bei Werbeaktionen und Mitgliedschaftsänderungen auf dem MySQL-Server ermöglichte.

Unsere Implementierung von Raft für MySQL basiert auf Apache Kudu. Wir haben es erheblich für die Anforderungen von MySQL und unserer Bereitstellung erweitert. Wir haben diesen Fork als Open-Source-Projekt, kuduraft, veröffentlicht.

Einige der wichtigsten Funktionen, die wir zu kuduraft hinzugefügt haben, sind:

Wir mussten auch relativ große Änderungen an der MySQL-Replikation vornehmen, um eine Schnittstelle zu Raft herzustellen. Zu diesem Zweck haben wir ein neues Closed-Source-MySQL-Plugin namens MyRaft erstellt. MySQL würde über die Plugin-APIs mit MyRaft kommunizieren (ähnliche APIs wurden auch für Semisync verwendet), während wir eine separate API für MyRaft erstellt haben, um eine Verbindung mit dem MySQL-Server herzustellen (Rückrufe).

Ein Raft-Ring würde aus mehreren MySQL-Instanzen (vier im Diagramm) in verschiedenen Regionen bestehen. Die Kommunikationsumlaufzeit (RTT) zwischen diesen Regionen würde zwischen 10 und 100 Millisekunden liegen. Einige dieser MySQLs (normalerweise drei) durften zu Primärservern werden, während der Rest nur reine Lesereplikate (nicht primärfähig) sein durfte. Für die MySQL-Bereitstellung bei Meta besteht seit langem auch die Forderung nach Commits mit extrem geringer Latenz. Die Dienste, die MySQL als Speicher verwenden (z. B. der Social Graph), benötigen oder wurden für solche extrem schnellen Schreibvorgänge entwickelt.

Um diese Anforderung zu erfüllen, würde die Konfiguration von FlexiRaft nur In-Region-Commits verwenden (dynamischer Modus für eine einzelne Region). Um dies zu ermöglichen, hätte jede primär fähige Region zwei zusätzliche Logtailer (Zeugen oder Nur-Log-Entitäten). Das Datenquorum für Schreibvorgänge beträgt 2/3 (2 ACKs von 1 MySQL + 2 Logtailer). Raft würde weiterhin ein repliziertes Protokoll über alle Entitäten hinweg verwalten und ausführen (1 primärfähiges MySQL + 2 Logtailer) * 3 Regionen + (nicht primärfähiges MySQL) * 3 Regionen = 12 Entitäten.

Floßrollen: Der Anführer ist, wie der Name schon sagt, der Anführer in einem Begriff des replizierten Protokolls. Ein führender Anbieter in Raft wäre auch der primäre Anbieter in MySQL und derjenige, der Client-Schreibvorgänge akzeptiert. Der Follower ist ein stimmberechtigtes Mitglied des Rings und empfängt passiv Nachrichten (AppendEntries) vom Anführer. Ein Follower wäre aus der Sicht von MySQL eine Replik und würde die Transaktionen auf seine Engine anwenden. Es würde keine direkten Schreibvorgänge von Benutzerverbindungen zulassen (read_only=1 ist gesetzt). Ein Lernender wäre ein nicht stimmberechtigtes Mitglied des Rings, z. B. die drei MySQLs in nicht primärfähigen Regionen (oben). Aus MySQL-Sicht wäre es eine Nachbildung.

Für die Replikation hat MySQL in der Vergangenheit das binäre Protokollformat verwendet. Dieses Format ist für die Replikation von MySQL von zentraler Bedeutung und wir haben beschlossen, es beizubehalten. Aus der Raft-Perspektive wurde das Binärprotokoll zum replizierten Protokoll. Dies wurde über die Protokollabstraktionsverbesserung von Kuduraft erreicht. Die MySQL-Transaktionen würden als eine Reihe von Ereignissen (z. B. Update Rows-Ereignis) mit einem Start und einem Ende für jede Transaktion codiert. Das Binärprotokoll hätte auch entsprechende Header und würde normalerweise mit einem Endereignis (Rotate-Ereignis) enden.

Wir mussten optimieren, wie MySQL seine Protokolle intern verwaltet. Auf einer Primärseite würde Raft in ein Binlog schreiben. Dies unterscheidet sich nicht von dem, was in Standard-MySQL geschieht. In einer Replik würde Raft auch in ein Binlog schreiben, statt in ein separates Relay-Log im Standard-MySQL. Dies führte zu einer Vereinfachung für Raft, da es nur einen Namensraum für Protokolldateien gab, um den sich Raft kümmern musste. Wenn ein Follower zum Anführer befördert würde, könnte er nahtlos in seinen Protokollverlauf zurückkehren, um Transaktionen an zurückgebliebene Mitglieder zu senden. Die Anwendungsthreads des Replikats würden Transaktionen aus dem Binlog abrufen und sie dann auf die Engine anwenden. Während dieses Vorgangs wird eine neue Protokolldatei, das Apply-Protokoll, erstellt. Dieses Anwendungsprotokoll würde eine wichtige Rolle bei der Wiederherstellung von Replikaten nach einem Absturz spielen, ansonsten handelt es sich jedoch um eine nicht replizierte Protokolldatei.

Zusammenfassend also:

Im Standard-MySQL:

In MySQL Raft:

Die Transaktion würde zunächst in der Engine vorbereitet. Dies würde im Thread der Benutzerverbindung passieren. Der Vorgang der Vorbereitung der Transaktion würde Interaktionen mit der Speicher-Engine (z. B. InnoDB oder MyRocks) umfassen und eine speicherinterne Binlog-Nutzlast für die Transaktion generieren. Zum Zeitpunkt des Commits würde der Schreibvorgang den Gruppen-Commit/ordered_commit-Flow durchlaufen. GTIDs würden zugewiesen, und dann würde Raft der Transaktion eine OpId (Begriff:Index) zuweisen. An diesem Punkt würde Raft die Transaktion komprimieren, in seinem LogCache speichern und die Transaktion in eine Binlog-Datei schreiben. Es würde asynchron damit beginnen, die Transaktion an andere Follower zu versenden, um ACKs zu erhalten und einen Konsens zu erzielen.

Der Benutzerthread, der sich im „Commit“-Modus der Transaktion befindet, würde blockiert und auf den Konsens von Raft warten. Wenn Raft zwei von drei Stimmen in der Region erhalten würde, würde ein Konsens erreicht werden. Raft würde die Transaktion auch an alle Mitglieder außerhalb der Region versenden, deren Stimmen jedoch aufgrund eines Algorithmus namens FlexiRaft (unten beschrieben) ignorieren. Beim Konsens-Commit würde der Benutzer-Thread entsperrt und die Transaktion würde fortgesetzt und an die Engine übergeben. Nach dem Commit der Engine wird die Schreibabfrage beendet und an den Client zurückgegeben. Bald darauf würde Raft auch asynchron einen Commit-Marker (OpId des aktuellen Commits) an nachgeschaltete Follower senden, damit diese die Transaktionen auch auf ihre Datenbank anwenden können.

Es mussten Änderungen an der Absturzwiederherstellung vorgenommen werden, damit sie nahtlos mit Raft funktioniert. Während der Laufzeit einer Transaktion kann es jederzeit zu Abstürzen kommen und daher muss das Protokoll die Konsistenz der Mitglieder gewährleisten. Hier sind einige wichtige Erkenntnisse darüber, wie wir es geschafft haben.

Failover und regelmäßige Wartungsvorgänge können Führungswechsel in Raft auslösen. Nachdem ein Anführer gewählt wurde, würde das MyRaft-Plugin versuchen, das zugehörige MySQL in den Primärmodus zu überführen. Zu diesem Zweck orchestriert das Plugin eine Reihe von Schritten. Diese Rückrufe von Raft → MySQL würden Transaktionen im laufenden Betrieb abbrechen, verwendete GTIDs zurücksetzen, das Engine-Seitenprotokoll von Apply-Log auf Binlog umstellen und schließlich die richtigen read_only-Einstellungen festlegen. Dieser Mechanismus ist komplex und derzeit nicht als Open-Source-Lösung verfügbar.

Da das Raft-Papier und Apache Kudu nur ein einziges globales Quorum unterstützten, würde es bei Meta nicht gut funktionieren, wo die Ringe groß waren, aber das Datenpfad-Quorum klein sein musste.

Um dieses Problem zu umgehen, haben wir FlexiRaft innoviert und dabei Ideen von Flexible Paxos übernommen.

Auf hoher Ebene ermöglicht FlexiRaft Raft, ein anderes Daten-Commit-Quorum (klein) zu haben, aber einen entsprechenden Einfluss auf das Leader-Wahl-Quorum (groß) zu erleiden. Durch die Einhaltung nachweisbarer Garantien für die Quorum-Schnittmenge stellt FlexiRaft sicher, dass die längsten Log-Regeln von Raft und die entsprechende Quorum-Schnittmenge nachweisbare Sicherheit gewährleisten.

FlexiRaft unterstützt den dynamischen Einzelregionsmodus. In diesem Modus werden die Mitglieder nach ihrer geografischen Region gruppiert. Das aktuelle Quorum von Raft hängt davon ab, wer der aktuelle Anführer ist (daher der Name „Single-Region-Dynamik“). Das Datenquorum ist die Mehrheit der Wähler in der Region des Führers. Bei Beförderungen, bei denen die Amtszeiten fortlaufend sind, schneidet der Kandidat mit der Region des letzten bekannten Anführers zusammen. FlexiRaft würde außerdem sicherstellen, dass auch das Quorum der Region des Kandidaten erreicht wird, andernfalls könnte die nachfolgende No-Op-Nachricht hängen bleiben. Wenn im seltenen Fall die Terme nicht kontinuierlich sind, würde Flexi Raft versuchen, eine wachsende Menge von Regionen zu ermitteln, die aus Sicherheitsgründen gekreuzt werden müssen, oder im schlimmsten Fall auf den N-Region-Schnittpunktfall von Flexible Paxos zurückgreifen . Aufgrund von Vorwahlen und Scheinwahlen kommt es selten zu Amtszeitlücken.

Um Promotion- und Mitgliedschaftsänderungsereignisse im Binlog zu serialisieren, haben wir das Rotate Event und Metadata Event des MySQL-Binärprotokollformats gekapert. Diese Ereignisse würden das Äquivalent von No-Op-Nachrichten und Add-Member-/Remove-Member-Vorgängen von Raft enthalten. Apache Kudu unterstützte keinen gemeinsamen Konsens, daher erlauben wir nur einzelne Mitgliedschaftsänderungen (Sie können die Mitgliedschaft nur einer Entität in einer Runde ändern, um den Regeln der impliziten Quorum-Schnittmenge zu folgen).

Mit der Implementierung von MySQL Raft haben wir eine sehr klare Trennung der Belange für die MySQL-Bereitstellung erreicht. Der MySQL-Server wäre für die Sicherheit über die replizierte Zustandsmaschine von Raft verantwortlich. Die Garantie ohne Datenverlust wäre nachweislich im Server selbst verankert. Automatisierung (Python-Skripte, Daemons) würde den Betrieb der Steuerungsebene initiieren und den Zustand der Flotte überwachen. Es würde auch Mitglieder ersetzen oder Werbeaktionen über Raft durchführen, während Wartungsarbeiten oder wenn ein Host-Ausfall festgestellt wurde. Hin und wieder könnte die Automatisierung auch die regionale Platzierung der MySQL-Topologie verändern. Die Änderung der Automatisierung zur Anpassung an Raft war ein gewaltiges Unterfangen, das sich über mehrere Jahre der Entwicklungs- und Einführungsbemühungen erstreckte.

Bei längeren Wartungsereignissen würde die Automatisierung Führungsverbotsinformationen für Raft festlegen. Raft würde diesen verbotenen Einheiten die Führung verweigern oder sie im Falle einer unbeabsichtigten Wahl umgehend evakuieren. Die Automatisierung würde auch von diesen Regionen weg und in andere Regionen vordringen.

Die Einführung von Raft in der Flotte war für das Team eine große Lernerfahrung. Wir haben Raft zunächst auf MySQL 5.6 entwickelt und mussten auf MySQL 8.0 migrieren.

Eine der wichtigsten Erkenntnisse war, dass Korrektheit mit Raft zwar leichter zu begründen war, das Raft-Protokoll an sich jedoch im Hinblick auf die Verfügbarkeit nicht viel hilft. Da unser MySQL-Datenquorum sehr klein war (zwei von drei Mitgliedern in der Region), könnten zwei schlechte Entitäten in der Region das Quorum ziemlich zerstören und die Verfügbarkeit beeinträchtigen. Die MySQL-Flotte erfährt täglich eine erhebliche Fluktuation (aufgrund von Wartungsarbeiten, Hostausfällen, Neuverteilungsvorgängen), daher waren die schnelle und korrekte Initiierung und Durchführung von Mitgliedschaftsänderungen eine Schlüsselvoraussetzung für eine ständige Verfügbarkeit. Ein großer Teil der Rollout-Bemühungen konzentrierte sich darauf, Logtailer und MySQL umgehend zu ersetzen, damit die Raft-Quoren gesund waren.

Wir mussten kuduraft verbessern, um es robuster für die Verfügbarkeit zu machen. Diese Verbesserungen waren nicht Teil des Kernprotokolls, können aber als technische Ergänzungen dazu betrachtet werden. Kuduraft hat die Unterstützung für Vorwahlen, aber Vorwahlen finden nur während eines Failovers statt. Bei einem eleganten Führungswechsel geht der designierte Kandidat direkt zu einer echten Wahl über, wodurch die Amtszeit verlängert wird. Dies führt zu steckengebliebenen Anführern (Kuduraft führt kein automatisches Absenken durch). Um dieses Problem anzugehen, haben wir eine Funktion für Scheinwahlen hinzugefügt, die den Vorwahlen ähnelte, jedoch nur bei einem ordnungsgemäßen Führungswechsel stattfand. Da es sich um einen asynchronen Vorgang handelte, kam es nicht zu längeren Ausfallzeiten bei der Promotion. Eine Scheinwahl würde Fälle aussortieren, in denen eine echte Wahl teilweise erfolgreich wäre und stecken bliebe.

Umgang mit byzantinischen Fehlern: Die Mitgliederliste von Raft gilt als von Raft selbst gesegnet. Aber während der Bereitstellung neuer Mitglieder oder aufgrund von Rennen in der Automatisierung könnte es bizarre Fälle geben, in denen sich zwei verschiedene Raft-Ringe kreuzen. Diese Zombie-Mitgliedschaftsknoten mussten aussortiert werden und sollten nicht in der Lage sein, miteinander zu kommunizieren. Wir haben eine Funktion implementiert, um RPCs von solchen Zombie-Mitgliedern zum Ring zu blockieren. Dies war in gewisser Weise die Vorgehensweise eines byzantinischen Schauspielers. Wir haben die Raft-Implementierung verbessert, nachdem wir diese seltenen Vorfälle bei unserer Bereitstellung bemerkt hatten.

Eines der Ziele bei der Einführung von MySQL Raft bestand darin, die betriebliche Komplexität bei Bereitschaftsdiensten zu reduzieren, damit Ingenieure Probleme lokalisieren und entschärfen können. Wir haben mehrere Dashboards, CLI-Tools und Tauchtabellen erstellt, um Raft zu überwachen. Wir haben MySQL um eine umfangreiche Protokollierung erweitert, insbesondere im Bereich von Werbeaktionen und Mitgliedschaftsänderungen. Wir haben CLIs für Quorum- und Abstimmungsberichte zu einem Ring erstellt, die uns helfen, schnell zu erkennen, wann und warum ein Ring nicht verfügbar ist (zerbrochenes Quorum). Die Investition in die Werkzeug- und Automatisierungsinfrastruktur ging Hand in Hand und wäre möglicherweise eine größere Investition gewesen als die Serveränderungen. Diese Investition hat sich sehr gelohnt und die Betriebs- und Einarbeitungsprobleme reduziert.

Obwohl dies unerwünscht ist, kommt es hin und wieder zu Quoren, die zu einem Verlust der Verfügbarkeit führen. Der typische Fall ist, dass die Automatisierung fehlerhafte Instanzen/Logtailer im Ring nicht erkennt und diese nicht schnell ersetzt. Dies kann auf eine schlechte Erkennung, eine Überlastung der Worker-Warteschlange oder einen Mangel an freier Hostkapazität zurückzuführen sein. Korrelierte Ausfälle, bei denen mehrere Einheiten im Quorum gleichzeitig ausfallen, sind weniger typisch. Dies geschieht nicht oft, da bei den Bereitstellungen versucht wird, Fehlerdomänen durch geeignete Platzierungsentscheidungen auf kritische Einheiten des Quorums zu isolieren. Um es kurz zu machen: Im großen Maßstab passieren trotz bestehender Schutzmaßnahmen unerwartete Dinge. Es müssen Werkzeuge verfügbar sein, um solche Situationen in der Produktion zu entschärfen. Im Hinblick darauf haben wir Quorum Fixer entwickelt.

Quorum Fixer ist ein in Python erstelltes manuelles Korrekturtool, das die Schreibvorgänge im Ring unterdrückt. Es führt Out-of-Band-Prüfungen durch, um die längste Protokolleinheit zu ermitteln. Dadurch werden die Quorumserwartungen für eine Führungswahl innerhalb von Raft zwangsweise geändert, sodass die gewählte Einheit zum Leiter wird. Nach erfolgreicher Beförderung setzen wir die Quorumserwartung zurück und der Ring wird normalerweise wieder gesund.

Es war eine bewusste Entscheidung, dieses Tool nicht automatisch auszuführen, da wir die Ursache ermitteln und alle Fälle von Quorumverlust identifizieren und dabei Fehler beheben möchten (und diese nicht stillschweigend durch Automatisierung beheben lassen).

Der Übergang von semisynchronem zu MySQL Raft im Rahmen einer massiven Bereitstellung ist schwierig. Zu diesem Zweck haben wir ein Tool (in Python) namens „enable-raft“ erstellt. Enable-raft orchestriert den Übergang von semisynchron zu Raft, indem es das Plugin lädt und die entsprechenden Konfigurationen (MySQL-Systemvariablen) für jede der Entitäten festlegt. Dieser Vorgang bringt eine kleine Ausfallzeit für den Ring mit sich. Das Tool wurde im Laufe der Zeit robuster gemacht und kann Raft sehr schnell im großen Maßstab ausrollen. Wir haben es genutzt, um Raft sicher auszurollen.

Es erübrigt sich zu erwähnen, dass eine Änderung in der Kernreplikationspipeline von MySQL ein sehr schwieriges Projekt ist. Da die Datensicherheit auf dem Spiel steht, waren Tests der Schlüssel zum Vertrauen. Während des Projekts haben wir Schattentests und Fehlerinjektion erheblich genutzt. Vor jedem Rollout des RPM-Paketmanagers fügten wir Tausende von Failovers und Wahlen in Testringe ein. Wir würden Ersetzungen und Mitgliedschaftsänderungen an den Testressourcen auslösen, um die kritischen Codepfade auszulösen.

Auch Langzeittests mit Datenkorrektheitsprüfungen waren von entscheidender Bedeutung. Wir verfügen über eine Automatisierung, die jede Nacht auf den Shards läuft und so die Konsistenz von Primär- und Replikaten gewährleistet. Wir werden auf jede solche Diskrepanz aufmerksam gemacht und beheben sie.

Die Leistung der Schreibpfadlatenz für Raft entsprach der von Semisync. Die Semisync-Maschinerie ist etwas einfacher und dürfte daher schlanker sein. Wir haben Raft jedoch optimiert, um die gleichen Latenzen wie Semisync zu erzielen. Wir haben kuduraft so optimiert, dass der Flotte keine weitere CPU hinzugefügt wird, obwohl viele weitere Verantwortlichkeiten übernommen wurden, die zuvor außerhalb der Server-Binärdatei lagen.

Raft hat die Werbeaktionen und Failover-Zeiten um ein Vielfaches verbessert. Anmutige Beförderungen, die den Großteil der Führungswechsel in der Flotte ausmachen, haben sich deutlich verbessert, und wir können eine Beförderung normalerweise in 300 Millisekunden abschließen. Da in den semisynchronen Setups der Service Discovery Store die Quelle der Wahrheit wäre, würden die Clients das Ende der Promotion viel länger bemerken, was zu längeren Ausfallzeiten der Endbenutzer auf einem Shard führen würde.

Raft führt normalerweise innerhalb von 2 Sekunden einen Failover durch. Dies liegt daran, dass wir alle 500 Millisekunden einen Heartbeat für die Gesundheit des Rafts durchführen und eine Wahl starten, wenn drei aufeinanderfolgende Heartbeats fehlschlagen. In der semisync-Welt war dieser Schritt sehr orchestrierungsintensiv und dauerte 20 bis 40 Sekunden. Raft sorgte dadurch für eine zehnfache Verbesserung der Ausfallzeiten bei Failover-Fällen.

Raft hat dazu beigetragen, Probleme bei der Betriebsverwaltung von MySQL bei Meta zu lösen, indem es nachweislich Sicherheit und Einfachheit bietet. Unsere Ziele, die MySQL-Konsistenz selbst verwalten zu können und über Tools für die seltenen Fälle von Verfügbarkeitsverlusten zu verfügen, werden größtenteils erreicht. Raft eröffnet uns nun für die Zukunft erhebliche Chancen, da wir uns auf die Verbesserung des Angebots für die Dienste konzentrieren können, die MySQL verwenden. Eine der Forderungen unserer Serviceeigentümer ist eine konfigurierbare Konsistenz. Durch die konfigurierbare Konsistenz können die Eigentümer zum Zeitpunkt des Onboardings auswählen, ob der Dienst X-Region-Quoren benötigt oder Quoren, die Kopien in bestimmten Regionen (z. B. Europa und den Vereinigten Staaten) anfordern. FlexiRaft bietet nahtlose Unterstützung für solche konfigurierbaren Quoren und wir planen, diese Unterstützung in Zukunft einzuführen. Solche Quoren führen entsprechend zu höheren Commit-Latenzen, Anwendungsfälle müssen jedoch in der Lage sein, einen Kompromiss zwischen Konsistenz und Latenz zu finden (z. B. PACELC-Theorem).

Aufgrund der Proxying-Funktion (Fähigkeit, Nachrichten mithilfe einer Multihop-Verteilungstopologie zu senden) kann Raft auch Netzwerkbandbreite über den Atlantik einsparen. Wir planen, Raft nur einmal für die Replikation von den USA nach Europa zu verwenden und dann die Proxy-Funktion von Raft für die Verteilung innerhalb Europas zu nutzen. Dadurch erhöht sich die Latenz, aber sie wird nominell sein, da der Großteil der Latenz bei der transatlantischen Übertragung anfällt und der zusätzliche Hop viel kürzer ist.

Einige der spekulativeren Ideen in Metas Datenbankbereitstellungen und dem verteilten Konsensraum betreffen die Erforschung führerloser Protokolle wie Epaxos. Unsere aktuellen Bereitstellungen und Dienste haben mit den Annahmen gearbeitet, die mit starken Leader-Protokollen einhergehen, aber wir sehen allmählich eine Reihe von Anforderungen, bei denen Dienste von einer gleichmäßigeren Schreiblatenz im WAN profitieren würden. Eine weitere Idee, die wir in Betracht ziehen, besteht darin, das Protokoll von der Zustandsmaschine (der Datenbank) in ein disaggregiertes Protokoll-Setup zu entkoppeln. Dadurch kann das Team die Belange des Protokolls und der Replikation getrennt von den Belangen des Datenbankspeichers und der SQL-Ausführungs-Engine verwalten.

Der Aufbau und die Bereitstellung von MySQL Raft im Meta-Maßstab erforderte erhebliche Teamarbeit und Managementunterstützung. Wir möchten den folgenden Personen für ihre Rolle danken, die zum Erfolg dieses Projekts beigetragen hat. Shrikanth Shankar, Tobias Asplund, Jim Carrig, Affan Dar und David Nagle für die Unterstützung der Teammitglieder auf dieser Reise. Wir möchten uns auch bei den fähigen Programmmanagern dieses Projekts, Dan O und Karthik Chidambaram, bedanken, die uns auf dem Laufenden gehalten haben.

Der technische Aufwand umfasste wichtige Beiträge mehrerer aktueller und ehemaliger Teammitglieder, darunter Vinaykumar Bhat, Xi Wang, Bartholomew Pelc, Chi Li, Yash Botadra, Alan Liang, Michael Percy, Yoshinori Matsunobu, Ritwik Yadav, Luqun Lou, Pushap Goyal und Anatoly Karp Igor Pozgaj.

AKTIE