Portál AbcLinuxu, 2. května 2025 20:40
Předumpování databáze, aneb bude to brnkačka
19.6.2020 08:03
| Přečteno: 2067×
|
Rád se podělím o jednu epizodu z práce adminstrátorské, protože obsahuje pár technických zvrat(k)ů a možná i obecné životní poučení :)
Začátek
Kolega se snažil zkopírovat jednu instanci databáze do druhé. Jenže se mu to pořád nedařilo. Řešili to na poradách už asi tři týdny a pořád žádný výsledek. Už od začátku jsem v hlavě tušil, že bych hravě zvládnul, ale sám toho mám hodně a vůbec, tenhle projekt není moje starost. Jenže to porady pořád natahovalo a už to začínal být opruz i pro mě. Tak jsem se do toho vložil a dobrovolně se nabídl, že vyřeším.
O co jde
Jedná se o jednu Percona 5.6, čistě InnoDB databázi, ve které začalo konstantně leakovat místo na disku:
Projekt trochu znám a tušil jsem, že tam bude hodně databází a tabulek. Řešení za mě je komplet předumpování do nové čisté instance. Kolega zkoušel všelijak binárně a pomocí replikace bez výpadku, ale nikam se nedostal. A vůbec, dump je grunt, jak říkal můj dědeček administrátor. Navíc jsem se cítil silný v kramflecích, už jsem toto v menším měřítku párkrát dělal.
Prvotní zmapování
Kontrola konfigurace ukázala, že až na pár rychlostních optimalizací je DB nastavena správně (innodb_file_per_table!). Počet databází: 5 000, počet tabulek v nich: 550 000, největší tabulka ne více, než 500MB, naprostá většina mnohem méně. Výpis se dá získat takto:
SELECT
concat(table_schema, '.', table_name) tbl,
engine,
concat(round(table_rows/1000000,2),'M') rows,
concat(round(data_length/(1024*1024*1024),2),'G') DATA,
concat(round(index_length/(1024*1024*1024),2),'G') idx,
concat(round((data_length+index_length)/
(1024*1024*1024),2),'G') total_size,
round(index_length/data_length,2) idxfrac
FROM information_schema.TABLES
WHERE table_schema not in
('mysql', 'performance_schema', 'information_schema')
ORDER BY data_length+index_length DESC;
BTW toto SQL běželo půl hodiny.
Plán akce
Mysqldump po databázích ukazuje něco přes 8 hodin. Tudy cesta nevede, ale to jsem věděl už od začátku a měl připravené řešení: budu dumpovat po jednotlivých tabulkách parelelně a získám tím potřebnou rychlost. Projekt snese pár hodin výpadku mezi druhou až dejme tomu pátou ráno. Mým cílem ale bylo ne déle, než 2 hodiny. Mám na to už hotovou kostru skriptu, hlavní práci odvádí tato část:
while read -r db tabulka; do
(( i++ ))
echo "(${i} / ${tabulky_pocet}) ${db}.${tabulka}"
while (( $(jobs -p | wc -l) >= $POCET_PARALELNICH )); do
sleep 0.1
done
predumpuj "$db" "$tabulka" &
done <<< "$tabulky"
wait
echo "Done"
Mysqldump sype data rourou rovnou do nové DB.
Skript mám hotový relativně brzo, dodělal jsem do něj hlavně zobrazení ETA a průměrné rychlosti, přeci jen chci u takto velké DB vidět nějaký progress.
První test
Jde se na první spuštění, díky --skip-lock-tables pro mysqldump můžu i v produkční době, navíc server má výkonu dost.
POCET_PARALELNICH nastavuji na 20, po zkoušce jestli server nespadl dávám 40 a vypadá ještě trochu rychlejší. Nyní dumpuje rychlostí cca 100 tabulek za vteřinu v průměru. Jsem nadšen a ruším limit na prvních 10 000 tabulek a chci nechat předumovat všech 550 000.
Dump běží krásně a už si plánuju budíka na druhou ráno, že rovnou překlopím. Jenže ...
Bash bug?
Průměrná rychlost postupně klesá a ETA se prodlužuje, ale to přisuzuji faktu, že narážím na tabulky, které jsou trochu větší. Jenže rychlost klesá pořád až se ETA blíží ke třem hodinám. To jsme na cca 50 000 tabulkách a rychlost je zhruba na polovině. Podezírám databáze, zkouším všechno možné ale děje se pořád. Až mě napadá: třeba to brzdí samotný bash? Chvíli exerimentuji s různými implementacemi paralelizace ve skriptu, ale posun žádný. Až google:
https://unix.stackexchange.com/questions/573315/bash-script-that-runs-parallel-threads-slows-down-substantially-over-several-hou
Tak je to přece jen bash! Naštěstí v odkazu výše jsou uvedené možné alternativy, jako první volím pro paralelizaci xargs.
Jiná paralelizace
Přepis do xargsu už je rychlovka, hlavní část vypadá takto:
echo "$tables" | awk '{ i++; printf("%s %s %s\n", i, $1, $2) }' | xargs -n 3 -P "$POCET_PARALELNICH" ./predumpuj-worker.bash
výstup workeru loguji takto přímo v něm:
flock /root/predumpuj_worker.log echo "${1} ${2} ${3} ${ret}" >> /root/predumpuj_worker.log
Díky tomuto logu a příkazu pv mám i jednoduchý progress i s ETA:
tail -n0 -f /root/predumpuj_worker.log | pv -l -s 550000 > /dev/null
Takto už šlape plnou rychlostí po celou dobu a plánuji ostré překlopení na druhou ráno. Čas celého dumpu: cca 70 minut. Skript je takto i mnohem kratší a elegantnější.
První ostrý pokus
Budík mě probudil, ale vstával bych stejně - dělal jsem něco i pro jiného zákazníka. Vše jde dobře a pouštím dump. ETA najednou 3.5 hodiny. WTF? Výkon na serveru je, disky stíhají (SSD), proč to najednou nejde?
Po hodině se nelepší, tak celou akci odvolávám.
Čím to je?
Celá akce už jde mnohem složitěji, než jsem čekal. Trochu se toho začínám bát, že bych to nakonec nezvládl? Co bylo na ostrý pokus jinak? Až mi to na procházce dochází: předchozí pokusy nanečisto jsem dělal do prázdné databáze, zatímco ráno jsem zapisoval do databáze už jednou dumpnuté. Další testy tezi potvrzují - přepis dat je mnohem pomalejší, než zápis na čisto.
Druhý ostrý pokus
Budík vzbudil, začátek dobrý :) Dump frčí krásně, ETA dokonce 65 minut. Za 63 minut předumpováno, dělá tedy průměrně 145 tabulek za vteřinu.
Zajímavost: v každém běhu cca 100-200 tabulek selže dump. Díky logu dohledám a pustím jejich dump znovu. Nyní proběhnou. Asi tam v prvním průběhu nejsou nějaké potřebné závislosti v databázi.
Konec a poučení?
Akce tedy proběhla, zabrané místo na disku se opět vrátilo do normálu a už se neztrácí do neznáma. A poučení? Byl jsem si až příliš jistý, že se snadno podaří :) A možná taky, že i v bashi (čemkoli) může být bug. A nakonec - když nevíš, použij google, už to určitě někdo řešil! :)
Bonus na závěr
Tato publikace zvedla naše znalosti MySQL/Percona na novou úroveň:
Google: Speedemy-MySQL-Configuration-Tuning-Handbook.pdf
Určitě doporučuji.
Tiskni
Sdílej:
Komentáře
Vložit další komentář
19.6.2020 09:11
z_sk | skóre: 34
| blog:
analyzy
Re: Předumpování databáze, aneb bude to brnkačka
19.6.2020 09:21
petr
Re: Předumpování databáze, aneb bude to brnkačka
19.6.2020 11:03
Max | skóre: 72
| blog:
Max_Devaine
Re: Předumpování databáze, aneb bude to brnkačka
19.6.2020 11:24
johnyK | skóre: 2
| blog:
uxblog
Re: Předumpování databáze, aneb bude to brnkačka
19.6.2020 15:53
trekker.dk | skóre: 72
Re: Předumpování databáze, aneb bude to brnkačka
19.6.2020 19:03
Odin1918 | skóre: 6
| blog:
Valhalla
Re: Předumpování databáze, aneb bude to brnkačka
Založit nové vlákno •
Nahoru
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.