Wie man Master in MySQL Master-Slave bestimmt


17

Ich richte die MySQL Master-Slave-Replikation ein und versuche herauszufinden, wie ich mit der Failover-Situation umgehen kann, in der ich den Slave zum Master befördere (für den Fall, dass der Master ausfällt).

Mein Anwendungsserver muss alle Schreibvorgänge an den aktuellen Master leiten, aber ich kann die Serverebene HA zwischen Master und Slave (Heartbeat, Keepalived) nicht verwenden, da sich die beiden Datenbankserver in völlig unterschiedlichen Subnetzen an verschiedenen physischen Standorten befinden.

Ich denke, das ist etwas, was ich auf Anwendungsebene behandeln muss. Ich kann die beiden Server abfragen und fragen, welcher ein Master ist, und dann alle Abfragen an diesen durchführen.

Gibt es in MySQL eine Abfrage, ob der aktuelle Server ein Master in einem Master-Slave-Replikat ist?


Welche Version von MySQL benutzt du ???
RolandoMySQLDBA

Dies ist MySQL-AusgabeServer version: 5.5.23 MySQL Community Server (GPL)
Ethan Hayon

Antworten:


13

@RolandoMySQLDBA hat die Frage genau beantwortet ... aber er wies auch darauf hin, dass seine Lösung "schnell und schmutzig" war.

Und das ist eine sehr wahre Aussage. :)

Was mich hier beschäftigt, ist nicht diese Antwort, sondern die Tatsache, dass die ursprüngliche Frage eine falsche Annahme zu machen scheint:

Ich kann die beiden Server abfragen und fragen, welcher ein Master ist, und dann alle Abfragen an diesen durchführen.

Das Problem ist, dass der Master bei der MySQL-Replikation nie wirklich weiß, dass er der Master ist.

Das Konzept der "Beförderung zum Master" ist in der asynchronen Replikation von MySQL eigentlich kein Konzept. Das "Heraufstufen" eines MySQL-Servers zur Masterrolle geschieht "außerhalb" von MySQL-Servern und nicht "innerhalb" von MySQL-Servern.

Die "Beförderung zum Master" wird von keiner Serverbereitstellung durchgeführt, da technisch gesehen jeder MySQL-Server, auf dem die binäre Protokollierung aktiviert ist, ein Master ist, auch wenn er niemals einen Slave hat. SHOW MASTER STATUSArbeitet genau so und gibt genau das gleiche Ergebnis zurück, ob Slaves oder nicht, und ein Master mit 2 Slaves ist nicht mehr oder weniger ein Master als ein Master mit 1 Slave oder 0 Slaves. Ebenso ist ein Master, dessen Slaves alle offline sind, immer noch genauso ein Master, denn wenn die Slaves wieder online sind, wiederholen sie sich dort, wo sie aufgehört haben.

In gewisser Weise besteht die einzige "Erkenntnis" beider Server nicht darin, ob es sich um einen Master handelt, sondern ob es sich um einen Slave handelt (oder nicht).

Das ist, was Rolando Lösung fragt: "Bist du ein Sklave?" Wenn die Antwort nein ist, dann ist die Annahme, dass dies der Meister sein muss ... was er auch als fehlerhafte Annahme bezeichnet, wenn STOP SLAVE;ausgegeben wird. Aber ein angehaltener Sklave ist immer noch ein Sklave, so dass "kein Sklave" (zu jedem Zeitpunkt) nicht mit "ein Meister sein" gleichzusetzen ist.

Ein ähnlicher Test könnte am vermuteten Master durchgeführt werden:

SELECT COUNT(1) FROM information_schema.processlist
 WHERE user = 'the_username_used_by_the_slave';

oder

SELECT COUNT(1) FROM information_schema.processlist
 WHERE command = 'binlog dump';

Wenn der Wert Null ist, ist der IO-Thread des Slaves nicht verbunden. Dieser Test weist einen ähnlichen Fehler auf: Wenn der Slave administrativ getrennt, isoliert oder ausgefallen ist, wird keine Verbindung hergestellt. Das löst also auch nichts.

Schlimmer noch (für eines dieser Szenarien): Die "Tabelle" information_schema.processlist ist eine virtuelle Tabelle, die bei jeder Auswahl materialisiert wird. Dies kostet Zeit und Ressourcen. Je geschäftiger Ihr Server ist, desto höher sind die Kosten, da in die Aktivitäten jedes Threads eingesehen werden muss.

Eine leichtere Lösung wäre:

SELECT @@global.read_only;

Auf einem Slave könnten / sollten Sie die globale Variable read_onlyso einstellen , dass Benutzer ohne die SUPERBerechtigung nicht unbeabsichtigt darauf schreiben können (und Ihre Anwendung sollte dies nicht haben SUPER). Wenn Sie den Slave manuell in die Master-Rolle "befördern", müssen Sie SET GLOBAL read_only = OFFSchreibvorgänge aktivieren. (Die Replikation kann immer in den Slave schreiben, egal wie dies eingestellt ist).

Aber ich denke, das geht noch an einem wichtigen Punkt vorbei:

Ich würde vorschlagen, dass die Anwendung diese Entscheidung nicht heuristisch in einem Master / Slave-Setup und erst recht nicht verbindungsweise treffen sollte. Die Anwendung sollte entweder eine feste Konfigurationsoption verwenden, oder die Anwendung sollte nichts davon wissen und das Datenbankverbindungsziel von etwas anderem behandeln lassen.

Oder zumindest sollte die Anwendung niemals umschalten, bis der Master ausfällt, und dann sollte sie niemals von selbst zurückschalten.

Hier ist der Grund, warum ich das sage: Sobald die "Entscheidung" - von wem oder was auch immer - getroffen wurde, einen anderen Server zum Master zu machen, kann die Anwendung aus keinem Grund zum ursprünglichen Master zurückkehren, selbst nachdem sie wieder online ist , ohne einzugreifen.

Angenommen, Sie haben einen Fehler gefunden und es kommt zu einem Absturz, der durch Software erzwungen wird. mysqld_safeDer Neustart von mysqldInnoDB ist pflichtgemäß und die Wiederherstellung nach einem Absturz funktioniert einwandfrei. Das dauert aber ein paar Minuten.

In der Zwischenzeit ist der Master heruntergefahren, sodass Ihre Anwendung auf den Slave umgeschaltet hat. Transaktionen wurden erstellt, Bestellungen aufgegeben, Gelder überwiesen, Kommentare gepostet, Blogs bearbeitet, was auch immer Ihr System tut.

Jetzt ist der ursprüngliche Master wieder online.

Wenn Ihre Anwendung auf den ursprünglichen Master zurückschaltet, befinden Sie sich in einer Welt voller Verletzungen, da die Replikation als Nächstes wahrscheinlich aufgrund einer Inkonsistenz gestoppt wird, da Ihre Anwendung in der Zwischenzeit Daten auf dem Slave geändert hat Zeit. Sie haben jetzt zwei Datenbankserver mit inkonsistenten Daten, die Sie manuell abgleichen müssen. Wenn es sich um Dollars, Punkte oder Guthaben handelt, sind die Kontostände nicht mehr aufeinander abgestimmt.

Daher ist es wichtig, dass die Anwendung nicht ohne Ihr Zutun zum ursprünglichen Master zurückkehren kann.

Warten Sie, haben Sie gerade das Problem mit diesem Szenario gefunden, wie ich es beschrieben habe? Der Master ist ausgefallen, aber Ihre Anwendung verwendet den Slave nicht, da sie denkt, der Slave sei immer noch der Slave und nicht der Master. Die information_schema.processlistAbfrage auf dem Slave wird immer noch ungleich Null zurückgegeben, auch wenn der Master-Server ausgeschaltet ist .

Es macht also nicht viel Sinn, wenn die Anwendung etwas entdeckt, da Sie STOP SLAVEdiesen Test manuell durchführen müssen , um ihn zu nutzen.

Ein besserer Ansatz, wenn Sie möchten, dass die Anwendung wechseln kann, besteht darin, die Server mit zirkulärer Replikation zu konfigurieren.

Die zirkuläre Replikation weist eigene Probleme auf. Solange Ihre Anwendung jedoch immer nur auf einen Server gleichzeitig schreibt, sind die meisten dieser Probleme keine Probleme. Mit anderen Worten, beide Maschinen sind im Sinne der Replikation immer und gleichzeitig Master und Slave, aber Ihre Anwendung zeigt über einen Mechanismus immer nur auf eine Maschine zu einem Zeitpunkt als den "Master", auf den sie schreiben kann und sollte .

Sie können HA-Tools aufgrund ihrer Trennung nicht auf den MySQL-Servern bereitstellen, aber Sie können sie mit HAProxy implementieren, das auf den Anwendungsservern ausgeführt wird. Die Anwendung stellt eine Verbindung zu "MySQL" auf localhost her, das überhaupt nicht MySQL ist, sondern eigentlich HAProxy ... und leitet die TCP-Verbindung an den entsprechenden MySQL-Rechner weiter.

HAProxy kann die Verbindungen zu den MySQL-Servern testen und nur Datenverkehr zu einem MySQL-Computer anbieten, der Verbindungen akzeptiert und die Authentifizierung zulässt.

Die Kombination aus HAProxy, das auf dem Anwendungsserver ausgeführt wird (sein Ressourcenbedarf ist im Vergleich zu allem, was der Anwendungsserver zu tun hat, nicht wesentlich - es bindet einfach Sockets zusammen und ignoriert deren Nutzlast) ... und MySQL-Umlaufreplikation wäre der Ansatz, den ich wahrscheinlich in diesem Fall wählen würde, basierend auf dem, was aus der Frage bekannt ist.

Oder gehen Sie für eine streng manuelle Einrichtung mit etwas viel Einfacherem als "Erkennen" vor, wie einem Eintrag in der /etc/hostsDatei des App-Servers mit einem Hostnamen, den die Anwendung verwendet, um eine Verbindung zu MySQL herzustellen, den Sie manuell aktualisieren könnten - vorausgesetzt, Sie befördern den Slave zu Master soll ein manueller Prozess sein.

Oder etwas Komplexeres mit Percona XtraDB Cluster. Hierfür möchten Sie jedoch einen dritten Server hinzufügen, da bei 3 Knoten in PXC, wenn 2 Server sich sehen können, aber von 1 Server isoliert sind (wenn alle drei Server noch ausgeführt werden), die 2 Server weiterhin problemlos ausgeführt werden Der 1 Server rollt sich zu einem kleinen Ball zusammen und weigert sich, etwas zu tun, da er feststellt, dass es der seltsame sein muss. Dies funktioniert, weil die 2 erkennen, dass sie immer noch die Mehrheit der Knoten darstellen, die vor dem Aufteilen des Netzwerks online waren, und die 1 erkennt, dass dies nicht der Fall ist. Bei PXC spielt es keine Rolle, zu welchem ​​Server Ihre Anwendung eine Verbindung herstellt.

Ich sage das alles, um zu sagen: "Lassen Sie die Server nicht von der Anwendung abfragen, um herauszufinden, welcher der Master ist", weil er Sie früher oder später beißt und Ihre Leistung bis zu dem Tag beeinträchtigt, an dem er beißt.


Zunächst einmal vielen Dank für die gut geschriebene Antwort. Ich denke, Sie haben eine gute Lösung vorgeschlagen. Ich habe in der Vergangenheit über die Verwendung der zirkulären Replikation nachgedacht, aber schlechte Dinge in Bezug auf die Zuverlässigkeit gelesen. Viele dieser Probleme können jedoch durch Ändern von auto_increment_increment, auto_increment_offset usw. verhindert werden. Die lokale Verwendung von HAProxy auf den Anwendungsservern (nur als Failover) würde für uns gut funktionieren, da wir unsere Anwendung nicht ändern und daher das Failover abstrahieren müssten Logik von der Anwendungsschicht entfernt. Ich werde mich um die Konfiguration von HAProxy kümmern, danke!
Ethan Hayon

1
Froh, dass ich Helfen kann. Eine positive Abstimmung wäre wünschenswert, wenn Sie dies noch nicht getan haben. Die zirkuläre Replikation ist genauso zuverlässig wie Master / Slave (dieselbe Technologie, nur in beide Richtungen), sofern Sie wissen, wie sie funktioniert und wie Sie sie sinnvoll einsetzen. Solange die Server ordnungsgemäß synchronisiert sind und die Anwendung jeweils nur auf einen Server schreibt, hatte ich nie ein Problem damit. Die auto_increment_*Variablen sind in diesem Szenario "nur für den Fall" noch gut zu verwenden. Denken Sie auch daran, binlog_format= rowoder mixed- nicht zu verwenden statement(auch wenn Sie kein Zirkelzeichen verwenden).
Michael - Sqlbot

Ich habe die akzeptierte Antwort nur deshalb geändert, weil mir diese detaillierte Erklärung dabei geholfen hat, das System robuster zu gestalten. @ RolandoMySQLDBAs Antwort ist immer noch richtig und löst das Problem, das ich anfangs beschrieben habe. Vielen Dank!
Ethan Hayon

10

Wenn Sie nur Master / Slave verwenden, ist hier etwas schnelles und schmutziges:

SELECT COUNT(1) SlaveThreadCount
FROM information_schema.processlist
WHERE user='system user';

Was sagt dir das?

  • Wenn SlaveThreadCount= 0, haben Sie den Master
  • Wenn SlaveThreadCount> 0, haben Sie den Slave

CAVEAT : Dies funktioniert, solange Sie nicht ausgeführt werdenSTOP SLAVE;

Eine andere Sache, die Sie versuchen sollten, ist folgende: Wenn Sie die Binärprotokollierung auf dem Slave deaktivieren und ausführen SHOW MASTER STATUS;, zeigt der Master das aktuelle Binärprotokoll an. Der Sklave gibt dir nichts.


Genial, genau das brauche ich. Denken Sie, dass dies eine unordentliche Lösung für das Problem ist? Das einzige Problem, das ich mir vorstellen kann, ist, dass beide Server zum Master befördert werden, aber das sollte eigentlich nie passieren.
Ethan Hayon

Wenn Sie diese Antwort benötigen, markieren Sie bitte die akzeptierte Antwort, indem Sie auf das Häkchen bei meiner Antwort klicken.
RolandoMySQLDBA

Ich kann es nicht für weitere 5 Minuten als akzeptiert markieren :)
Ethan Hayon

Kein Problem. Ich war froh, dass ich helfen konnte !!!
RolandoMySQLDBA

0

Führen Sie diese Anweisung über die mysql-Eingabeaufforderung
mysql> show slave status aus.

Auf dem Slave werden viele Parameter und deren Werte / Status angezeigt, während auf dem Master der leere Satz angezeigt wird

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.