Úvod
Ahoj. Jsem ningenMe, webový vývojář.
Jak již název napovídá, můj příběh je příběhem o fyzickém odstranění 300 milionů záznamů v MySQL.
Zaujal mě tento problém, a proto jsem se rozhodl vytvořit příručku.
Začátek — Upozornění
V dávkovém serveru, který používám a spravuji, existuje pravidelný proces, který jednou denně shromažďuje data za poslední měsíc z MySQL.
Obvykle tento proces trvá přibližně 1 hodinu, ale tentokrát to trvalo 7 nebo 8 hodin, a upozornění neustále přicházela…
Hledání příčiny
Zkusil jsem restartovat proces, podívat se do logů, ale nic podezřelého jsem nenašel.
Dotaz se indexoval správně. Ale když jsem přemýšlel o tom, co není v pořádku, uvědomil jsem si, že objem databáze je dost velký.
hoge_table | 350'000'000 |350 milionů záznamů. Zdá se, že indexace fungovala správně, jen velmi pomalu.
Potřebný sběr dat za měsíc činil přibližně 12 000 000 záznamů. Vypadá to, že dotaz SELECT trval dlouho a transakce se vykonávala jen těžce.
DB
V podstatě je to tabulka, která každý den narůstá přibližně o 400 000 záznamů. Databáze měla shromažďovat data pouze za poslední měsíc, tedy byla počítána na to, že bude zvládat právě tento objem dat, ale bohužel nebyla zahrnuta operace ROTATE.
Tato databáze byla navržena nikým jiným než mnou. Převzal jsem ji od jiného vývojáře, což zanechalo pocit technického dluhu.
Nastal okamžik, kdy objem denně vkládaných dat vzrostl a konečně dosáhl limitu. Předpokládá se, že při práci s tak velkým objemem dat by se měla data rozdělovat, ale to bohužel nebylo uděláno.
A tady jsem vstoupil do procesu já.
Oprava
Bylo rozumnější zmenšit samotnou databázi a zkrátit čas na její zpracování, než měnit samotnou logiku.
Situace by se měla výrazně změnit, pokud smažeme 300 milionů záznamů, proto jsem se rozhodl to udělat… Ach, myslel jsem, že to určitě zabere.
Akce 1
Po přípravě spolehlivé zálohy jsem konečně začal odesílat dotazy.
„Odeslání dotazu“
DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';「…」
「…」
„Hmm… Žádná odpověď. Možná proces trvá delší dobu?“ — pomyslel jsem si, ale pro jistotu jsem se podíval do Grafany a viděl, že zatížení disku velmi rychle rostlo.
„Nebezpečné,“ pomyslel jsem si znovu a okamžitě zastavil dotaz.
Akce 2
Po analýze všeho jsem pochopil, že objem dat byl příliš velký na to, abych odstranil všechno najednou.
Rozhodl jsem se napsat skript, který bude schopen odstranit přibližně 1 000 000 záznamů, a spustil jsem ho.
„implementuji skript“
„Teď to určitě vyjde,“ pomyslel jsem si.
Akce 3
Druhá metoda zafungovala, ale byla velmi pracná.
Abych to udělal důkladně, bez zbytečných nervů, trvalo by to asi dva týdny. Ale tento scénář stále neodpovídal požadavkům služby, takže jsem se od něj musel odchýlit.
Proto jsem se rozhodl udělat toto:
Zkopírujeme tabulku a přejmenujeme ji.
Z předchozího kroku jsem pochopil, že odstranění tak velkého objemu dat vytváří stejně velké zatížení. Tak jsem se rozhodl vytvořit novou tabulku od nuly pomocí insert a přesunout do ní data, která jsem chtěl odstranit.
| hoge_table | 350'000'000|
| tmp_hoge_table | 50'000'000|Pokud vytvořím novou tabulku o velikosti, jak je uvedeno výše, rychlost zpracování dat by také měla být 1/7 rychlejší.
Poté, co jsem tabulku vytvořil a přejmenoval, začal jsem ji používat jako hlavní tabulku. Teď, pokud odstraním tabulku s 300 miliony záznamů, mělo by být všechno v pořádku.
Zjistil jsem, že truncate nebo drop vytvářejí menší zátěž než delete, a rozhodl jsem se použít tento přístup.
Provedení
„Odeslání dotazu“
INSERT INTO tmp_hoge_table SELECT * FROM hoge_table WHERE create_time > 'YYYY-MM-DD HH:MM:SS'; 「…」
「…」
„ehm…?“
Akce 4
Myslel jsem, že předchozí nápad bude fungovat, ale po odeslání insert dotazu se objevila víc než jedna chyba. MySQL nešetří.
Byl jsem už tak unavený, že jsem začal uvažovat, že tohle už dělat nechci.
Chvíli jsem přemýšlel a pochopil jsem, že možná pro jednorázový dotaz bylo insertů příliš mnoho…
Zkusil jsem odeslat insert dotaz na objem dat, který by databáze měla zpracovat za 1 den. A povedlo se!
A potom pokračujeme v odesílání dotazů na stejný objem dat. Protože potřebujeme odstranit měsíční objem dat, opakujeme tuto operaci přibližně 35krát.
Přejmenování tabulky
Zde měla štěstí na mé straně: všechno proběhlo hladce.
Alert zmizel.
Rychlost dávkového zpracování se zvýšila.
Kdysi tento proces trval asi hodinu, nyní zabere přibližně 2 minuty.
Poté, co jsem se ujistil, že jsou všechny problémy vyřešeny, jsem smazal 300 milionů záznamů. Smazal jsem tabulku a cítil se jako znovuzrozený.
Shrnutí
Uvědomil jsem si, že při dávkovém zpracování došlo k opomenutí rotate processing, což byla hlavní příčina problému. Taková architektonická chyba vede k prázdné ztrátě času.
Zamysleli jste se někdy nad zátěží při replikaci dat, když mažete záznamy z databáze? Pojďme nepřetěžovat MySQL.
Ti, kdo se dobře orientují v databázích, se s takovým problémem jistě nesetkají. Ostatním doufám, že tento článek byl užitečný.
Děkujeme za přečtení!
Budeme velmi rádi, pokud nám řeknete, zda se vám tento článek líbil, zda byl překlad srozumitelný a zda vám byl užitečný?
Zdroj: habr.com
