Auf der Website und im Online-Shop "Eldorado" werden täglich etwa 40.000 Einkäufe getätigt. Es ist wahrscheinlich nicht erforderlich zu erklären, was dies für das Geschäft des Unternehmens bedeutet.
In der Vergangenheit läuft der Store auf der Bitrix-Engine mit einer großen Menge an benutzerdefiniertem Code und Add-Ons. Der Speicher ist ein MySQL-Cluster mit vier Master-Servern.
Eine bedeutende Anzahl von Unternehmen hat monolithische Anwendungen, und viele müssen mit ihnen arbeiten. Es gibt viele Möglichkeiten, mit dem Monolithen umzugehen, aber leider schreiben nur wenige über erfolgreiche. Ich hoffe, dass die Geschichte darüber, wie wir unseren Monolithen stützen (bis wir ihn gesehen haben), für Sie von Interesse sein wird.
Wir sind uns bewusst, dass massive Architektur viele Probleme mit sich bringen kann. Aber es ist leicht, es zu zerstören, durch eine einfache willensstarke Entscheidung ist es unmöglich: Der Verkauf läuft, die Website muss funktionieren, Änderungen für Benutzer dürfen nicht radikal sein. Daher braucht der Übergang von einem Monolithen zu einer Reihe von Mikrodiensten Zeit, die wir aushalten müssen: um sicherzustellen, dass das System betriebsbereit ist und seine Belastbarkeit aufweist.
Was war das Problem
Der Datenbankcluster auf der eldorado.ru-Website wurde sehr lange nach folgendem Schema erstellt:
Alle Master in diesem Schema arbeiten gleichzeitig und alle befinden sich im aktiven Modus und spielen nacheinander den Replikationsstrom ab ... M1-> M2- > M3-> M4-> M1 -> M2-> M3-> M4-> M1-> M2 ...
In unserem Setup gab diese Konfiguration das einzige Plus - sie ermöglichte es dem System, zu arbeiten und seine Last zu halten. Tatsache ist, dass der Application Request Balancer nach jeder Aktualisierung zur Gewährleistung der Konsistenz den gesamten Lesestream auf diesen Master umschaltet und ein Master einmal nicht ausreichte, um den gesamten Lesestream zu speichern.
Ein solches Schema könnte jedoch weder Zuverlässigkeit noch Arbeitsgeschwindigkeit bieten. Obwohl es einfach aussah, hatte es eine Reihe von Mängeln. Sie aktualisierte die Daten im Cluster nur sehr langsam: Im schlimmsten Fall gab es bis zu fünf Replikationsarme (je nachdem, auf welchem Master die Änderungen ursprünglich initiiert wurden). Aufgrund dieser Verzögerungen traten viele Probleme sowohl beim Betrieb der Website als auch bei der Bestellung im Online-Shop auf.
Nachteile dieses Schemas :
- Die Slaves der Zone, die am weitesten vom aktiven Master entfernt ist, erhalten im schlimmsten Fall erst nach der vierfachen Transaktionsausführungszeit Datenaktualisierungen. Manchmal kam es zu rasenden Replikationsverzögerungen.
- Jeder Fehler auf einem der Master führt zu Dateninkonsistenzen im gesamten Cluster, bis diese behoben sind.
- (- — );
- ;
- , ( , , );
- UPDATE/DELETE SELECT ;
- , slave_status seconds_behind_master.
Sie können dieses Verhalten in Ihren Testumgebungen emulieren, indem Sie eine künstliche Replikationsverzögerung von 1-2 Sekunden auf den Slaves aktivieren (was wir getan haben). Dies ist eine hervorragende Möglichkeit, Ihre Anwendung mit der Option MASTER_DELAY = N auf Bereitschaft für solche verteilten Architekturen zu testen .
und schließlich ist der Übergang in unserem Fall in einer anderen Datenbank keine Option, da das System zu groß angelegte ist und viel in Bezug auf die Nutzung von MySQL gebunden verfügt und sogar auf die Nuancen seiner internen Abfrage - Optimierer.
Wie wir es gelöst haben
Wir wollten das Schema nicht selbst ändern (dies ist eine riskante Operation) und suchten zunächst nach einem Beratungsunternehmen, das eine neue Architektur vorschlagen und bereitstellen kann, damit die Site weiterhin zugänglich ist und der Wechsel nicht erkennbar ist. Unter diesen Unternehmen befanden sich die größten Integratoren und Softwareentwickler.
Einige Unternehmen haben uns einfach nicht geantwortet (und das ist normal), während andere geschrieben haben, dass sie nicht bereit sind, eine solche Aufgabe zu übernehmen. Gleichzeitig stellte sich nicht einmal die Frage nach den möglichen Kosten des Projekts.
Wenn große Integratoren sich nicht auf eine Aufgabe einlassen wollen, ist es doppelt interessant geworden, sie selbst zu lösen. Wir hatten eine gute Ausrüstung zur Verfügung, Probleme mit Stabilität und Fehlertoleranz standen an zweiter Stelle, und am Anfang wollten wir die Datenübertragung irgendwie beschleunigen. Einige Optionen, die in den MySQL-Versionen 5.6 und 5.7 erschienen sind, haben hierfür gut funktioniert.
Die Dokumentation deutete zwar transparent an, dass es nicht möglich wäre, sie einfach zu aktivieren, tk. Im Ring wird es definitiv einen Sklaven mit einer kleineren Version geben, aber hier ist es so:
Der 5.7-Master kann die alten Binärprotokolle lesen, die vor dem Upgrade geschrieben wurden, und sie an die 5.7-Slaves senden. Die Slaves erkennen das alte Format und behandeln es richtig.
Vom Master nach dem Upgrade erstellte Binärprotokolle haben das Format 5.7. Auch diese werden von den 5.7-Slaves erkannt.
Mit anderen Worten, beim Upgrade auf MySQL 5.7 müssen die Slaves MySQL 5.7 sein, bevor Sie den Master auf 5.7 aktualisieren können.
Für Tests genügte es uns, den Testring beispielsweise über mysqld_multi zu erhöhen und typische Abfragen darauf auszuführen (Sie können sogar auf demselben Host 4 Instanzen an verschiedenen Ports mit unterschiedlichen Offset-Sätzen ausführen).
mysql -h127.0.0.1 -P 3302 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3302 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3301, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master1-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3303 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3303 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3302, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master2-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3304 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3304 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3303, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master3-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3301 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3301 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3304, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master4-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
Danach können Sie die Version einer beliebigen Instanz ändern, indem Sie die Konfiguration mit dem gewünschten Port mit einer anderen Binärdatei ausführen, die daneben platziert wurde, und mysql_upgrade für die Daten- / Systemtabellen erstellen.
Im Verkauf könnten wir für eine begrenzte Zeit den gesamten Datenverkehr nur an einen Master senden, zu diesem Zeitpunkt einen anderen aktualisieren, dann zu diesem wechseln und alle anderen erneut aktualisieren. Dafür musste jedoch die Kompatibilität des binlog-Formats zwischen den Versionen sichergestellt werden, damit absolut alle Transaktionen erfolgreich verloren gingen.
Ein wenig mehr Dokumentation nützlich für unseren Fall:
Um Inkompatibilitäten zu vermeiden, legen Sie die folgenden Variablen auf dem MySQL 5.6-Master fest:
binlog_checksum=NONE binlog_row_image=FULL binlog_rows_query_log_events=OFF log_bin_use_v1_row_events=1 (NDB Cluster only)
Dieses Flag hat sich für uns als obligatorisch erwiesen, obwohl wir keine NDB verwenden. Ohne dieses Flag wurde die Replikation zwischen den Servern 5.6 - 5.5 beendet und mysqlbinlog liest das Protokoll ohne diese Option mit dem Fehler ERROR: Error in Log_event :: read_log_event () : 'Sanity Check fehlgeschlagen', data_len: 8203, event_type: 30, wenn aktiviert, startet und funktioniert alles.
Wir haben die GTID nicht aufgenommen, weil Neben der Forderung nach Kompatibilität mit allen alten Werkzeugen sehen wir objektiv nicht genügend Vorteile für den Übergang.
gtid_mode=OFF
Der einfachste Test, um die Richtigkeit der Replikation zu überprüfen, besteht darin, einen Speicherauszug der Reihe nach auf den Server mit 5.5 und den Server mit 5.6 hochzuladen und zu prüfen, ob alles in Ordnung ist.
Leider waren die Tests, obwohl erwartet, nicht erfolgreich.
Last_Error: Column 18 of table 'eldorado2.b_adv_banner' cannot be converted from type '<unknown type>' to type 'datetime'
Die Datumszeit in 5.6 ist etwas Besonderes. Es werden Mikrosekunden hinzugefügt. In 5.6 gibt es eine neue Datumszeit, die in
Version 5.6, Version 5.6 , unbekannt ist. Sie kann parallel zu 5.5 in einem Cluster in einem Ring arbeiten, wenn gleichzeitig keine Felder erstellt werden in einer der Tabellen, die die Replikation mit neuen Feldtypen durchlaufen. (datetime 5.6! = datetime 5.5, ähnlich wie time, timestamp, es gibt mehr als 240 solcher Felder in unserer Datenbank).
Wir konnten das Fehlen von DDL in diesen Feldern nicht vollständig garantieren und wollten die Leistung des gesamten Clusters nicht gefährden. Aber wir hatten einen sichereren Plan B.
Es bedeutete das Vorhandensein zusätzlicher Hardware für Manöver und das Erstellen einer vollständigen Kopie des Clusters in der Nähe. Glücklicherweise hatten wir solche Hardware. Und da es eine solche Möglichkeit gibt, war es notwendig, sofort einen "normalen" Cluster zu erstellen.
Gleichzeitig ist es jedoch erforderlich, die Funktionsfähigkeit aller aktuellen Überwachungs-, Debugging- und Binlog-Analysetools zu gewährleisten und alle vorhandenen Mängel der aktuellen Architektur so weit wie möglich zu beseitigen.
Mehrkanalreplikation
Eine Silberkugel wird benötigt, um die Stellen intakt zu halten und die Admins zu füttern. Dies ist eine Mehrkanalreplikation. Wir vertrauten a priori neuen Möglichkeiten nicht und waren uns über die Technologie nicht sicher. Wir konnten solche Informationen oder Fälle nirgendwo finden. Es gibt wenig öffentliche Erfahrung in der großen Produktion.
Deshalb haben wir an alles selbst gedacht, der Plan war wie folgt:
- : 5.7, ;
- ;
- , — , , .
— , , , . , , ? . , « »! , - !
( « »)
In dem Zielschema sind 4 Master 4 unabhängige Aufzeichnungsströme für jeden Slave, die unabhängig verarbeitet werden.
Auf allen Mastern war es jetzt möglich, log_slave_updates zu deaktivieren - sie müssen einfach nirgendwo weiterleiten, sie senden alle Änderungen im Hauptstrom (=> die Belastung des Masters ist noch geringer).
Gleichzeitig können Sie auch das minimale Binlog-Format und die parallele Verarbeitung von Transaktionen auf dem Weg aktivieren (unter bestimmten Bedingungen müssen Sie es richtig verstehen):
slave_parallel_workers=5 slave_parallel_type=LOGICAL_CLOCK binlog_row_image=minimal
Mit diesem Setup können wir die Last jederzeit auf einen neuen Cluster umstellen, aber diese Route ist einseitig und sieht kein Rollback vor.
Für die Lebensdauer der Verbindungen zum alten Cluster ist die Option log_slave_updates an einem Master-Einstiegspunkt zum neuen Cluster noch vorhanden, und daher werden alle Änderungen von den Verbindungen zum "alten" Cluster perfekt an den neuen und unmittelbar danach übertragen Sie sterben aus dieser Option wurde deaktiviert, die Anwendung sah bis zu diesem Moment 3 andere Master und Datenströme kreuzten sich in keiner Weise.
Als Ergebnis haben wir die folgenden Vorteile erhalten:
- Wenn eine lange Anforderung etwas blockiert, betrifft dies nur einen von vier Replikationsthreads und die anderen in keiner Weise.
- Das neue Binlog-Format, das bisher nur aufgrund der MySQL-Version nicht möglich war, nimmt jetzt ein Vielfaches weniger Speicherplatz in Anspruch, und dementsprechend kann der Datenverkehr aufgrund dessen viel mehr Änderungen im gesamten Cluster passieren.
- Jetzt können Sie jeden Meister absolut schmerzlos ausschalten, ohne alles andere zu beeinflussen.
- Die Unfälle von Mastern sind jetzt nicht mehr so beängstigend. Jetzt können Sie jeden Server in einer Minute in einer unverständlichen Situation klonen, die server_id neu generieren, Credits für den Slave-Zugriff erstellen und - der neue Master ist bereit.
Es gibt auch ein "Minus":
- Jeder Master hat viel mehr Slaves und es ist einfacher, in den Kanal zu laufen (tatsächlich ist dies keine Zunahme des Verkehrs, sondern eine zeitliche und räumliche Umverteilung).
Was hat das neue System gebracht?
Die Umstellung auf das neue System erwies sich als erfolgreich. Wir haben es an einem Tag, dem 28. August 2020, durchgeführt. Die Erfahrung mit der Verwendung der neuen Architektur hat gezeigt, dass die Anzahl der Replikationsprobleme um das Drei- bis Vierfache reduziert wurde (es ist unmöglich, sie vollständig zu beseitigen). Die Stabilität des Systems hat zugenommen. Das Hauptergebnis war eine Erhöhung des maximalen Durchsatzes des Systems. Wenn frühere Entwickler unverständliche Probleme auf die Replikation zurückführen konnten, funktioniert dies jetzt nicht mehr für sie.
Die Anzahl der Client-Probleme, die durch Replikationsverzögerungen verursacht wurden, wurde um ein Vielfaches reduziert, was bedeutet, dass Clients zumindest etwas weniger Schmerzen haben. Jetzt können wir jeden Master-Server jederzeit ausschalten, um daran zu arbeiten. Dies wirkt sich nicht auf den gesamten Cluster aus und stoppt den Replikationsprozess nicht.
Der Cluster bedient den Hauptstandort "Eldorado" - größtenteils eine alte monolithische Anwendung mit Produktkarten, einem persönlichen Konto, einem Warenkorb, einer Bestellabwicklung, einem Callcenter usw. Zum Zeitpunkt dieses Schreibens beträgt die gesamte Leselast im Cluster (nur auf den Slaves) 40.000 U / min, ungefähr 5.000 U / min pro Datenbankserver, ohne die technische Belastung einzelner technischer Slaves, die in Spitzenzeiten erheblich höher ist. Es mag nicht viel erscheinen, aber man muss die Art und Komplexität dieser Abfragen berücksichtigen.
Wir hoffen wirklich, dass unsere Erfahrung jemandem nützlich sein wird. Neben der Mehrkanalreplikation verwenden wir auch viele interessante Dinge, wie z. B. Blackhole- und Verbundtabellen. Sie ermöglichen es Ihnen auch, viele Kopfschmerzen zu beseitigen (und ein wenig für diejenigen hinzuzufügen, die nicht verstehen, warum sie benötigt werden), wenn dies jemand ist interessiert an den Nuancen und anderen Fragen zu unserem MySQL - Willkommen in den Kommentaren.
Während eines halben Jahres im kommerziellen Betrieb sind noch keine Probleme im Zusammenhang mit Mehrkanälen aufgetreten, und wir können ein solches Setup definitiv als ausreichend fehlertolerant und zuverlässig empfehlen.
Der Monolith selbst ist gerade dabei, eine Reihe von separaten und unabhängigen Diensten zu zerschneiden, von denen wir einige aufteilen und Ihnen von unseren Erfahrungen erzählen werden - bleiben Sie dran.
Besonderer Dank geht an mein exzellentes Team, ohne sie hätten wir das nicht geschafft!
PS Übrigens brauchen wir immer noch wirklich talentierte Programmierer . Wenn Sie so sind, kommen Sie , es wird interessant sein.