Warum Seconds_Behind_Master immer noch 0 ist, wenn eine MySQL-Synchronisierungsverzögerung auftritt

Warum Seconds_Behind_Master immer noch 0 ist, wenn eine MySQL-Synchronisierungsverzögerung auftritt

Problembeschreibung

Der Benutzer hat einen Änderungsvorgang an der primären Datenbank durchgeführt, der etwa eine Stunde dauerte. Nachdem der Vorgang abgeschlossen ist, stellt die Slave-Datenbank fest, dass eine Synchronisierungsverzögerung vorliegt, aber der Indikator „Seconds_Behind_Master“ im Überwachungsdiagramm zeigt 0 an und die Verzögerungsdistanz des Binärprotokolls nimmt ständig zu.

Prinzipanalyse

Da wir die Verzögerungszeit analysieren, beginnen wir natürlich mit der Berechnung der Verzögerung. Der Einfachheit halber wird hier der Quellcode der offiziellen Version 5.7.31 zum Lesen zitiert. Hier finden Sie den Code zur Berechnung der Verzögerungszeit:

./sql/rpl_slave.cc

bool show_slave_status_send_data(THD *thd, Master_info *mi,
                                 char* io_gtid_set_buffer,
                                 char* sql_gtid_set_buffer)
......
wenn ((mi->get_master_log_pos() == mi->rli->get_group_master_log_pos()) &&
        (!strcmp(mi->get_master_log_name(), mi->rli->get_group_master_log_name())))
    {
      wenn (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT)
        Protokoll->Speichern(0LL);
      anders
        Protokoll->store_null();
    }
    anders
    {
      langer Zeitunterschied = ((lang)(Zeit(0) - mi->rli->letzter_Masterzeitstempel)
                       - mi->Uhrdifferenz mit Master);

      Protokoll->Speichern((langlang)(mi->rli->letzter_Master_Zeitstempel?
                                   max(0L, Zeitdifferenz) : 0));
    }
......

Aus der Berechnungsmethode von time_diff können wir feststellen, dass diese Verzögerung grundsätzlich eine Zeitdifferenz ist, und dann wird die Zeitdifferenz zwischen dem Master und dem Slave berechnet. Da es jedoch viele if-Anweisungen gibt, verwende ich die Kommentare in der Quellcodedatei:

  /*
     Der Pseudocode zur Berechnung von Seconds_Behind_Master:
     wenn (SQL-Thread läuft)
     {
       if (SQL-Thread hat alle verfügbaren Relay-Protokolle verarbeitet)
       {
         wenn (IO-Thread läuft)
            drucke 0;
         anders
            drucke NULL;
       }
        anders
          Berechnen Sie Seconds_Behind_Master.
      }
      anders
       drucke NULL;
  */

Es ist ersichtlich, dass die Berechnung von Seconds_Behind_Master in zwei Teile unterteilt ist:

  • Wenn der SQL-Thread normal ist und alle Relaylogs wiedergegeben werden, und wenn der IO-Thread normal ist, wird es direkt auf 0 gesetzt.
  • Wenn der SQL-Thread normal ist und alle Relaylogs wiedergegeben werden, der IO-Thread jedoch nicht normal ist, setzen Sie direkt NULL.
  • Wenn der SQL-Thread normal ist und nicht alle Relay-Protokolle erneut abgespielt wurden, wird die Verzögerungszeit berechnet.

Achten Sie dann bei der Berechnung der Verzögerungszeit am Ende auf die Bedeutung dieser Variablen:

  • Zeit (0): aktueller Zeitstempel im Zeitstempelformat.
  • last_master_timestamp: Der Zeitpunkt, zu dem dieses Ereignis in der Masterdatenbank ausgeführt wird, im Zeitstempelformat.
  • clock_diff_with_master: Die Zeitdifferenz zwischen Slave und Master, die beim Start des IO-Threads ermittelt wird.

Es ist ersichtlich, dass bei der Berechnung der Verzögerung der Wert tatsächlich dadurch erhalten wird, dass die Zeit, zu der das wiedergegebene Ereignis auf dem Master ausgeführt wird, von der Ortszeit des Slaves abgezogen und dann die Zeitdifferenz zwischen beiden ausgeglichen wird. Logischerweise gibt es kein Problem. Da time(0) und clock_diff_with_master normalerweise nicht falsch sein können, sollte das Problem dieses Mal bei last_master_timestamp liegen.

PS: Obwohl es meistens kein Problem gibt, nimmt time(0) die Ortszeit an. Wenn also ein Problem mit der Ortszeit des Slaves vorliegt, ist der Endwert auch falsch, aber das liegt nicht im Rahmen dieses Falls.

Finden Sie dann die Logik zur Berechnung des last_master_timestamp bei der Ausführung des Ereignisses. In Kombination mit den Kommentaren können wir feststellen, dass normale Replikation und parallele Replikation unterschiedliche Berechnungsmethoden verwenden. Die erste ist die normale Replikation und der Berechnungszeitpunkt liegt vor der Ausführung des Ereignisses:

./sql/rpl_slave.cc

......
  wenn (ev)
  {
    Aufzählung enum_slave_apply_event_and_update_pos_retval exec_res;

    ptr_ev= &ev;
    /*
      Auch wenn wir dieses Ereignis nicht ausführen, behalten wir den Master-Zeitstempel,
      damit die Sekunden hinter dem Master das richtige Delta zeigen (es gibt Ereignisse
      die nicht wiederholt werden, sodass wir immer wieder in Rückstand geraten).

      Handelt es sich um ein künstliches Ereignis oder um ein Relay-Log-Ereignis (vom IO-Thread generiert
      event) oder ev->when auf 0 gesetzt ist, oder ein FD vom Master, oder ein Heartbeat
      Ereignis mit Server-ID „0“, dann aktualisieren wir den letzten Master-Zeitstempel nicht.

      Bei paralleler Ausführung wird last_master_timestamp nur aktualisiert, wenn
      ein Job wird aus GAQ genommen. Wenn also last_master_timestamp 0 ist (was
      zeigt an, dass GAQ leer ist, alle Slave-Worker warten auf Ereignisse von
      der Koordinator), müssen wir es mit einem Zeitstempel vom ersten initialisieren
      Ereignis, das parallel ausgeführt werden soll.
    */
    wenn ((!rli->is_parallel_exec() || rli->last_master_timestamp == 0) &&
         !(ev->is_artificial_event() || ev->is_relay_log_event() ||
          (ev->common_header->when.tv_sec == 0) ||
          ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT ||
          ev->server_id == 0))
    {
      rli->last_master_timestamp = ev->common_header->when.tv_sec +
                                  (Zeit_t) ev->Ausführungszeit;
      DBUG_ASSERT(rli->last_master_timestamp >= 0);
    }
......

Der Wert von last_master_timestamp ist die Startzeit des Ereignisses plus die Ausführungszeit. In 5.7 hatten viele Ereignisse keinen Ausführungszeitwert. 8.0 fügt diesen Wert vielen Ereignissen hinzu, sodass dies als Vorteil des Upgrades auf 8.0 angesehen werden kann.

Die Berechnungsmethode der parallelen Replikation lautet wie folgt:

./sql/rpl\_slave.cc

......
  /*
    Wir müssen sicherstellen, dass dies an dieser Stelle nie aufgerufen wird, wenn
    cnt ist Null. Dieser Wert bedeutet, dass die Checkpoint-Informationen
    wird komplett zurückgesetzt.
  */

  /*
    Aktualisieren Sie den rli->last_master_timestamp, um den korrekten Seconds_behind_master zu melden.

    Wenn GAQ leer ist, setzen Sie es auf Null.
    Andernfalls aktualisieren Sie es mit dem Zeitstempel des ersten Jobs der Slave_job_queue
    die in der Funktion Log_event::get_slave_worker() zugewiesen wurde.
  */
  ts = rli->gaq->leer()
    ? 0
    : neu interpretieren_cast<Slave_job_group*>(rli->gaq->head_queue())->ts;
  rli->reset_notified_checkpoint(cnt, ts, brauche_Datensperre, true);
  /* Ende von "Koordinator::"commit_positions" */

......

Wenn in der Commit_Positions-Logik des Koordinators die Gaq-Warteschlange leer ist, wird der Last_Master_Timestamp direkt auf 0 gesetzt, andernfalls wird der Zeitstempel des ersten Jobs in der Gaq-Warteschlange ausgewählt. Es sollte hinzugefügt werden, dass diese Berechnung nicht in Echtzeit, sondern intermittierend erfolgt. Vor der Berechnungslogik steht die folgende Logik:

  /*
    Derzeit wird die Checkpoint-Routine vom SQL-Thread aufgerufen.
    Aus diesem Grund heißt diese Funktion Aufruf von entsprechenden Punkten
    im Ausführungspfad des SQL-Threads und die verstrichene Zeit wird berechnet
    Überprüfen Sie hier, ob es Zeit ist, es auszuführen.
  */
  set_timespec_nsec(&aktuelle_Uhr, 0);
  ulonglong diff = diff_timespec(&aktuelle_Uhr, &rli->letzte_Uhr);
  wenn (!force && diff < Punkt)
  {
    /*
      Wir müssen den Checkpoint jetzt nicht ausführen, weil
      die verstrichene Zeit reicht nicht aus.
    */
    DBUG_RETURN(FALSE);
  }

Das heißt, innerhalb des Zeitintervalls dieses Zeitraums wird es direkt zurückgegeben und der last_master_timestamp wird nicht aktualisiert. Daher werden Sie manchmal feststellen, dass sich der Wert von Seconds_Behind_Master bei der parallelen Replikation von Zeit zu Zeit von 0 auf 1 ändert.

Der Vorgang der gaq-Warteschlange ähnelt wahrscheinlich den Push- und Pop-Vorgängen des Stapels, sodass die in gaq verbleibenden Transaktionen immer nicht abgeschlossene Transaktionen sind. Daher ist die Zeitberechnung aus der Perspektive allgemeiner Szenarien in Ordnung.

Problemanalyse

Die Prinzipanalyse erläutert kurz die Logik der gesamten Berechnung. Kommen wir nun zur eigentlichen Frage zurück. Bei Tencent Cloud Database MySQL ist die parallele Replikation standardmäßig aktiviert, sodass eine gaq-Warteschlange vorhanden ist und der Änderungsvorgang sehr lange dauert. Unabhängig davon, ob der Änderungsvorgang in einer Gruppe paralleler Transaktionen ausgeführt wird (höchstwahrscheinlich ist DDL immer eine separate Transaktionsgruppe), ist die gaq-Warteschlange schließlich leer und last_master_timestamp wird auf 0 gesetzt. In Bezug auf die Berechnungslogik von Seconds_Behind_Master wird der endgültige time_diff ebenfalls auf 0 gesetzt, sodass die Verzögerungszeit vor dem Ende des Änderungsvorgangs immer 0 beträgt. Nachdem der Änderungsvorgang ausgeführt wurde, wird die Gaq-Warteschlange mit neuen Ereignissen und Transaktionen gefüllt, sodass die Verzögerung vorher möglicherweise 0 beträgt, aber plötzlich auf einen sehr hohen Wert springt.

Expandieren

Wenn wir die Unterschiede in den Berechnungsmethoden zwischen normaler Replikation und paralleler Replikation vergleichen, können wir die folgenden Merkmale erkennen:

  • Nach dem Aktivieren der parallelen Replikation springt die Verzögerungszeit häufig zwischen 0 und 1.
  • Bei Änderungsvorgängen und einzelnen großen Transaktionen kommt es in parallelen Replikationsszenarien häufig zu ungenauen Verzögerungen, bei normaler Replikation hingegen nicht.
  • Da die Master-Slave-Zeitdifferenz beim Starten des IO-Threads berechnet wird, weicht die Verzögerungszeit ebenfalls ab, wenn die Slave-Zeit während dieses Zeitraums abweicht.

Um zusammenzufassen

Für eine strenge Beurteilung der Verzögerung ist es besser, sich auf die GTID-Lücke und die Binlog-Positionslücke zu verlassen. Gemessen an den Änderungen der Ereignisausführungszeit in 8.0 arbeiten zumindest die Verantwortlichen von Oracle noch hart daran. Ich hoffe, diese kleineren Probleme können so schnell wie möglich behoben werden.

Oben finden Sie ausführliche Informationen dazu, warum Seconds_Behind_Master bei einer MySQL-Synchronisierungsverzögerung immer noch 0 ist. Weitere Informationen zur MySQL-Synchronisierungsverzögerung Seconds_Behind_Master ist 0 finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung von MySQLs Seconds_Behind_Master
  • Implementierungsmethode für Python3-Dateikopier- und verzögerte Dateikopieraufgaben
  • Beispielcode zur Implementierung der MySQL-Master-Slave-Replikation in Docker
  • MySQL-Datenbank Daten laden, vielfältige Verwendungsmöglichkeiten
  • MySQL-Datenbank Shell import_table Datenimport
  • Master-Slave-Synchronisationskonfiguration der Mysql-Datenbank
  • Beispielcode zur Implementierung einer einfachen Suchmaschine mit MySQL
  • Lösung für das Problem, dass MySQL-Befehle nicht auf Chinesisch eingegeben werden können
  • Als der Interviewer nach dem Unterschied zwischen char und varchar in mysql fragte
  • Zusammenfassung der Verzögerungen der MySQL-Slave-Bibliothek „Seconds_Behind_Master“

<<:  Beispielcode zur Implementierung des Dunkelmodus mit CSS-Variablen

>>:  Detaillierte Erklärung der JS-Array-Methoden

Artikel empfehlen

Erste Schritte Tutorial für Anfänger ④: So binden Sie Unterverzeichnisse

Um zu verstehen, was das bedeutet, müssen wir zunä...

Methode zur Wiederherstellung von Betriebs- und Wartungsdaten der MySQL-Datenbank

In den vorherigen drei Artikeln wurden gängige Si...

Erstellen eines FastDFS-Dateisystems in Docker (Tutorial mit mehreren Images)

Inhaltsverzeichnis Über FastDFS 1. Suche nach Bil...

js, um die Produktionsmethode des Karussells zu realisieren

In diesem Artikel wird der spezifische Code für j...

Lösen Sie das Problem des MySQL Threads_running-Surge und der langsamen Abfrage

Inhaltsverzeichnis Hintergrund Problembeschreibun...

So verwenden Sie JavaScript und CSS richtig in XHTML-Dokumenten

Auf immer mehr Websites wird HTML4 durch XHTML ers...

Detailliertes Tutorial zur Installation von InfluxDB in Docker (Leistungstest)

1. Voraussetzungen 1. Das Projekt wurde bereitges...

Umfassende Analyse der Isolationsebenen in MySQL

Wenn die Datenbank gleichzeitig denselben Datenst...

Aufbauprinzip des Nexus-Privatservers und Tutorial-Analyse

eins. Warum einen privaten Nexus-Server erstellen...