EinfĂŒhrung
Hallo. Ich bin ningenMe, ein Webentwickler.
Wie im Titel erwÀhnt, ist meine Geschichte die eines physischen Löschens von 300 Millionen DatensÀtzen in MySQL.
Ich war daran interessiert, also beschloss ich, eine Zusammenfassung (Anleitung) zu erstellen.
Beginn â Alarm
In dem Batch Server, den ich verwende und betreue, gibt es einen regelmĂ€Ăigen Prozess, der einmal tĂ€glich die Daten des letzten Monats aus MySQL abruft.
Normalerweise dauert dieser Prozess etwa 1 Stunde, aber diesmal dauerte er 7 oder 8 Stunden, und der Alarm hörte nicht auf zu erscheinen...
Ursachenanalyse
Ich habe versucht, den Prozess neu zu starten und die Protokolle zu ĂŒberprĂŒfen, aber ich konnte nichts Ungewöhnliches feststellen.
Die Abfrage war richtig indiziert. Aber als ich darĂŒber nachdachte, was schiefgeht, wurde mir klar, dass die Datenbank recht groĂ ist.
hoge_table | 350'000'000 |350 Millionen DatensÀtze. Es scheint, dass die Indizierung richtig funktionierte, nur sehr langsam.
Die benötigte Datensammlung fĂŒr den Monat betrug etwa 12.000.000 DatensĂ€tze. Es sieht so aus, als ob der SELECT-Befehl viel Zeit in Anspruch nahm und die Transaktion lange Zeit nicht ausgefĂŒhrt wurde.
DB
Im Grunde genommen handelt es sich um eine Tabelle, die jeden Tag um etwa 400.000 EintrÀge wÀchst. Die Datenbank sollte nur die Daten des letzten Monats sammeln, entsprechend wurde angenommen, dass sie mit diesem Datenvolumen umgehen kann, aber leider wurde die Rotate-Operation nicht aktiviert.
Diese Datenbank wurde nicht von mir entwickelt. Ich habe sie von einem anderen Entwickler ĂŒbernommen, weshalb das GefĂŒhl bleibt, dass es sich um technischen Schulden handelt.
Der Zeitpunkt kam, als das Volumen der tĂ€glich eingefĂŒgten Daten groĂ wurde und schlieĂlich einen Grenzwert erreichte. Man wĂŒrde erwarten, dass man bei so groĂen Datenmengen diese trennen sollte, aber leider wurde das nicht gemacht.
Und hier kam ich ins Spiel.
Korrektur
Es wĂ€re sinnvoller gewesen, die Datenbank selbst zu verkleinern und die Verarbeitungszeit zu verkĂŒrzen als die Logik zu Ă€ndern.
Die Situation sollte sich erheblich verĂ€ndern, wenn 300 Millionen EintrĂ€ge gelöscht werden, also entschied ich mich dafĂŒr⊠Ach, ich dachte, das wĂŒrde auf jeden Fall funktionieren.
Aktion 1
Nachdem ich ein zuverlĂ€ssiges Backup erstellt hatte, begann ich schlieĂlich, Anfragen zu senden.
ăAnfrage sendenă
DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';ăâŠă
ăâŠă
âHmm... Keine Antwort. Vielleicht dauert der Prozess zu lange?â â dachte ich, aber sicherheitshalber schaute ich in Grafana und sah, dass die Festplattenauslastung sehr schnell anstieg.
âDas ist riskantâ â dachte ich erneut und stoppte sofort die Anfrage.
Aktion 2
Nachdem ich alles analysiert hatte, stellte ich fest, dass das Datenvolumen zu groà war, um es auf einmal zu löschen.
Ich entschied mich, ein Skript zu schreiben, das etwa 1.000.000 EintrÀge löschen kann, und startete es.
ăSkript implementierenă
âJetzt wird es bestimmt funktionierenâ, â dachte ich.
Aktion 3
Die zweite Methode funktionierte, war aber sehr arbeitsintensiv.
Um alles ordentlich und ohne unnötigen Stress zu erledigen, brÀuchte es etwa zwei Wochen. Aber dennoch entsprach dieses Szenario nicht den Serviceanforderungen, weshalb ich davon Abstand nehmen musste.
Also, das habe ich beschlossen:
Tabelle kopieren und umbenennen
Aus dem vorherigen Schritt habe ich verstanden, dass das Löschen eines so groĂen Datenvolumens auch eine groĂe Last erzeugt. Daher entschied ich mich, eine neue Tabelle von Grund auf mit INSERT zu erstellen und die Daten, die ich löschen wollte, dorthin zu verschieben.
| hoge_table | 350'000'000|
| tmp_hoge_table | 50'000'000|Wenn ich eine neue Tabelle in der gleichen GröĂe wie oben angegeben erstelle, sollte die Datenverarbeitungsrate auch um 1/7 schneller sein.
Nachdem ich die Tabelle erstellt und umbenannt hatte, begann ich, sie als Mastertabelle zu nutzen. Jetzt, wenn ich die Tabelle mit 300 Millionen DatensÀtzen lösche, sollte alles in Ordnung sein.
Ich habe herausgefunden, dass truncate oder drop weniger Last erzeugt als delete und beschloss, diesen Ansatz zu verwenden.
AusfĂŒhrung
ăAnfrage sendenă
INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS'; ăâŠă
ăâŠă
âĂhmâŠ?â
Aktion 4
Ich dachte, die vorherige Idee wĂŒrde funktionieren, aber nach dem Senden der Insert-Anfrage trat ein mehrfacher Fehler auf. MySQL ist gnadenlos.
Ich bin so mĂŒde, dass ich anfing zu denken, dass ich keine Lust mehr darauf habe.
Ich habe nachgedacht und erkannt, dass es vielleicht bei einmal zu viele Insert-Anfragen warenâŠ
Ich habe versucht, eine Insert-Anfrage mit der Datenmenge zu senden, die die Datenbank an einem Tag verarbeiten sollte. Es hat geklappt!
Nach diesem Vorgang senden wir weiterhin Anfragen mit dem gleichen Datenvolumen. Da wir ein Monatsdatenvolumen entfernen mĂŒssen, wiederholen wir diesen Vorgang etwa 35 Mal.
Umbenennung der Tabelle
Hier hatte ich GlĂŒck: alles lief glatt.
Alert verschwunden
Die Verarbeitungszeit hat sich verkĂŒrzt.
FrĂŒher dauerte dieser Prozess etwa eine Stunde, jetzt dauert es ungefĂ€hr 2 Minuten.
Nachdem ich sichergestellt hatte, dass alle Probleme gelöst waren, habe ich 300 Millionen DatensĂ€tze gelöscht. Ich habe die Tabelle entfernt und fĂŒhlte mich neu geboren.
Zusammenfassung
Mir wurde klar, dass beim Batch-Processing das rotate processing ĂŒbersehen wurde, und das war das Hauptproblem. Ein solcher Architekturfefehl fĂŒhrt zu einer völligen Zeitverschwendung.
Machen Sie sich Gedanken ĂŒber die Last beim Replizieren von Daten, wĂ€hrend Sie DatensĂ€tze aus der Datenbank löschen? Lassen Sie uns MySQL nicht ĂŒberlasten.
Diejenigen, die sich gut mit Datenbanken auskennen, werden mit einem solchen Problem sicher nicht konfrontiert. Ich hoffe, dieser Artikel war fĂŒr die anderen hilfreich.
Vielen Dank fĂŒr das Lesen!
Wir wĂŒrden uns sehr freuen, wenn Sie uns mitteilen, ob Ihnen dieser Artikel gefallen hat, ob die Ăbersetzung verstĂ€ndlich war und ob er Ihnen hilfreich war.
Quelle: habr.com
