Jedním z klíčových faktorů výkonného databázového serveru MySQL je dobrá alokace a využití paměti, zejména při provozu v produkčním prostředí. Ale jak můžete zjistit, zda je využití MySQL optimalizováno? Je rozumné mít vysoké využití paměti nebo to vyžaduje jemné doladění? Co když narazím na únik paměti?
Pojďme pokrýt tato témata a ukázat věci, které můžete zkontrolovat v MySQL, abyste zjistili stopy vysokého využití paměti.
Alokace paměti v MySQL
Než se ponoříme do konkrétního názvu předmětu, poskytnu jen krátkou informaci o tom, jak MySQL využívá paměť. Paměť hraje významný zdroj rychlosti a efektivity při zpracování souběžných transakcí a spouštění velkých dotazů. Každé vlákno v MySQL vyžaduje paměť, která se používá ke správě klientských připojení, a tato vlákna sdílejí stejnou základní paměť. Proměnné jako thread_stack (zásobník pro vlákna), net_buffer_length (pro vyrovnávací paměť pro připojení a vyrovnávací paměť výsledků) nebo s max_allowed_packet, kde se připojení a výsledek v případě potřeby dynamicky zvětší až na tuto hodnotu, jsou proměnné, které ovlivňují využití paměti. Když vlákno již není potřeba, jemu přidělená paměť se uvolní a vrátí do systému, pokud vlákno nepřejde zpět do mezipaměti vláken. V takovém případě zůstane paměť přidělena. Spojení dotazů, mezipaměti dotazů, řazení, mezipaměť tabulek, definice tabulek vyžadují paměť v MySQL, ale jsou přiřazeny systémovým proměnným, které můžete nakonfigurovat a nastavit.
Ve většině případů jsou proměnné specifické pro paměť nastavené pro konfiguraci zaměřeny na konfiguraci specifickou pro úložiště, jako je MyISAM nebo InnoDB. Když se v hostitelském systému vytvoří instance mysqld, MySQL alokuje vyrovnávací paměti a mezipaměti pro zlepšení výkonu databázových operací na základě nastavených hodnot nastavených v konkrétní konfiguraci. Například nejběžnější proměnné, které každý DBA nastaví v InnoDB, jsou proměnné innodb_buffer_pool_size a innodb_buffer_pool_instances, které obě souvisí s alokací paměti fondu vyrovnávacích pamětí, která obsahuje data uložená v mezipaměti pro tabulky InnoDB. Je žádoucí, pokud máte velkou paměť a očekáváte, že budete zpracovávat velké transakce nastavením innodb_buffer_pool_instances, abyste zlepšili souběžnost rozdělením fondu vyrovnávacích pamětí do více instancí fondu vyrovnávacích pamětí.
Zatímco u MyISAM se musíte vypořádat s key_buffer_size, abyste zvládli množství paměti, kterou zvládne vyrovnávací paměť klíčů. MyISAM také přiděluje vyrovnávací paměť pro každé souběžné vlákno, které obsahuje strukturu tabulky, sloupcové struktury pro každý sloupec a vyrovnávací paměť o velikosti 3 * N (kde N je maximální délka řádku, nepočítaje sloupce BLOB). MyISAM také udržuje jednu vyrovnávací paměť řádku navíc pro interní použití.
MySQL také přiděluje paměť pro dočasné tabulky, pokud není příliš velká (určeno pomocí tmp_table_size a max_heap_table_size). Pokud používáte tabulky MEMORY a proměnná max_heap_table_size je nastavena velmi vysoko, může to také zabírat velkou paměť, protože systémová proměnná max_heap_table_size určuje, jak velká může tabulka narůst, a nedochází k převodu do formátu na disku.
MySQL má také Performance Schema, což je funkce pro monitorování aktivit MySQL na nízké úrovni. Jakmile je toto povoleno, dynamicky přiděluje paměť přírůstkově, čímž přizpůsobuje její využití paměti skutečnému zatížení serveru, namísto přidělování požadované paměti během spouštění serveru. Jakmile je paměť přidělena, není uvolněna, dokud není server restartován.
MySQL lze také nakonfigurovat tak, aby alokovalo velké oblasti paměti pro svůj fond vyrovnávacích pamětí, pokud používáte Linux a pokud je v jádře povolena podpora velkých stránek, tj. pomocí HugePages.
Co zkontrolovat, když je paměť MySQL vysoká
Zkontrolujte spuštěné dotazy
Pro správce MySQL je velmi běžné, že se nejprve dotknou základny toho, co se děje se spuštěným serverem MySQL. Nejzákladnějšími postupy jsou kontrola seznamu procesů, kontrola stavu serveru a kontrola stavu úložiště. K provedení těchto věcí v podstatě stačí spustit sérii dotazů přihlášením k MySQL. Viz níže:
Chcete-li zobrazit běžící dotazy,
mysql> SHOW [FULL] PROCESSLIST;
Zobrazení aktuálního seznamu procesů odhalí dotazy, které jsou spuštěny aktivně nebo dokonce nečinné nebo spící procesy. Je velmi důležité a je to významná rutina mít záznam o běžících dotazech. Jak bylo uvedeno o tom, jak MySQL alokuje paměť, spouštění dotazů bude využívat alokaci paměti a může způsobit drastické problémy s výkonem, pokud není monitorováno.
Zobrazit stavové proměnné serveru MySQL
mysql> SHOW SERVER STATUS\G
nebo filtrovat konkrétní proměnné jako
mysql> SHOW SERVER STATUS WHERE variable_name IN ('<var1>', 'var2'...);
Stavové proměnné MySQL slouží jako vaše statistické informace pro získávání metrických dat, abyste mohli určit výkon vašeho MySQL sledováním čítačů daných stavovými hodnotami. Jsou zde určité hodnoty, které vám poskytnou pohled, který má vliv na využití paměti. Například kontrola počtu vláken, počtu mezipamětí tabulek nebo využití fondu vyrovnávacích pamětí
...
| Created_tmp_disk_tables | 24240 |
| Created_tmp_tables | 334999 |
…
| Innodb_buffer_pool_pages_data | 754 |
| Innodb_buffer_pool_bytes_data | 12353536 |
...
| Innodb_buffer_pool_pages_dirty | 6 |
| Innodb_buffer_pool_bytes_dirty | 98304 |
| Innodb_buffer_pool_pages_flushed | 30383 |
| Innodb_buffer_pool_pages_free | 130289 |
…
| Open_table_definitions | 540 |
| Open_tables | 1024 |
| Opened_table_definitions | 540 |
| Opened_tables | 700887 |
...
| Threads_connected | 5 |
...
| Threads_cached | 2 |
| Threads_connected | 5 |
| Threads_created | 7 |
| Threads_running | 1 |
Zobrazení stavu monitoru enginu, například stav InnoDB
mysql> SHOW ENGINE INNODB STATUS\G
Stav InnoDB také odhaluje aktuální stav transakcí, které úložiště zpracovává. Poskytuje vám velikost haldy transakce, adaptivní hash indexy odhalující její využití vyrovnávací paměti nebo vám zobrazí informace o fondu vyrovnávací paměti innodb stejně jako v příkladu níže:
---TRANSACTION 10798819, ACTIVE 0 sec inserting, thread declared inside InnoDB 1201
mysql tables in use 1, locked 1
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 8801
MySQL thread id 68481, OS thread handle 139953970235136, query id 681821 localhost root copy to tmp table
ALTER TABLE NewAddressCode2_2 ENGINE=INNODB
…
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 528, free list len 43894, seg size 44423, 1773 merges
merged operations:
insert 63140, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 553193, node heap has 1 buffer(s)
Hash table size 553193, node heap has 637 buffer(s)
Hash table size 553193, node heap has 772 buffer(s)
Hash table size 553193, node heap has 1239 buffer(s)
Hash table size 553193, node heap has 2 buffer(s)
Hash table size 553193, node heap has 0 buffer(s)
Hash table size 553193, node heap has 1 buffer(s)
Hash table size 553193, node heap has 1 buffer(s)
115320.41 hash searches/s, 10292.51 non-hash searches/s
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2235564032
Dictionary memory allocated 3227698
Internal hash tables (constant factor + variable factor)
Adaptive hash index 78904768 (35404352 + 43500416)
Page hash 277384 (buffer pool 0 only)
Dictionary cache 12078786 (8851088 + 3227698)
File system 1091824 (812272 + 279552)
Lock system 5322504 (5313416 + 9088)
Recovery system 0 (0 + 0)
Buffer pool size 131056
Buffer pool size, bytes 2147221504
Free buffers 8303
Database pages 120100
Old database pages 44172
Modified db pages 108784
Pending reads 0
Pending writes: LRU 2, flush list 342, single page 0
Pages made young 533709, not young 181962
3823.06 youngs/s, 1706.01 non-youngs/s
Pages read 4104, created 236572, written 441223
38.09 reads/s, 339.46 creates/s, 1805.87 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 12 / 1000 not 5 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 120100, unzip_LRU len: 0
I/O sum[754560]:cur[8096], unzip sum[0]:cur[0]
…
Další věc, kterou je třeba přidat, můžete také použít schéma výkonu a schéma sys pro sledování spotřeby paměti a využití vaším serverem MySQL. Ve výchozím nastavení je většina přístrojů ve výchozím nastavení zakázána, takže pro použití této funkce je třeba udělat ručně.
Zkontrolujte výměnu
V každém případě je pravděpodobné, že MySQL vyměňuje paměť na disk. To je často velmi běžná situace, zvláště když MySQL server a základní hardware nejsou nastaveny optimálně paralelně s očekávanými požadavky. Existují určité případy, kdy se nepředpokládala poptávka po provozu, paměť by mohla narůstat, zejména pokud jsou spouštěny špatné dotazy, které spotřebovávají nebo využívají velké množství paměťového prostoru, což vede ke snížení výkonu, protože data jsou vybírána na disku místo ve vyrovnávací paměti. Chcete-li zkontrolovat swappiness, spusťte příkaz freemem nebo vmstat stejně jako níže,
[[email protected] ~]# free -m
total used free shared buff/cache available
Mem: 3790 2754 121 202 915 584
Swap: 1535 39 1496
[[email protected] ~]# vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 40232 124100 0 937072 2 3 194 1029 477 313 7 2 91 1 0
0 0 40232 123912 0 937228 0 0 0 49 1247 704 13 3 84 0 0
1 0 40232 124184 0 937212 0 0 0 35 751 478 6 1 93 0 0
0 0 40232 123688 0 937228 0 0 0 15 736 487 5 1 94 0 0
0 0 40232 123912 0 937220 0 0 3 74 1065 729 8 2 89 0 0
Můžete také zkontrolovat pomocí procfs a shromáždit informace, například přejít do /proc/vmstat nebo /proc/meminfo.
Použití Perf, gdb a Valgrind s Massif
Použití nástrojů jako perf, gdb a valgrind vám pomůže ponořit se do pokročilejší metody určování využití paměti MySQL. Jsou chvíle, kdy se zajímavý výsledek stává záhadou řešení spotřeby paměti, která vede k vašemu zmatku v MySQL. To vede k potřebě větší skepse a používání těchto nástrojů vám pomůže prozkoumat, jak MySQL využívá manipulaci s pamětí od její alokace až po její využití pro zpracování transakcí nebo procesů. To je užitečné například v případě, že pozorujete, že se MySQL chová abnormálně, což může způsobit špatnou konfiguraci nebo může vést ke zjištění úniků paměti.
Například použití perf v MySQL odhalí více informací ve zprávě na systémové úrovni:
[[email protected] ~]# perf report --input perf.data --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 54K of event 'cpu-clock'
# Event count (approx.): 13702000000
#
# Overhead Command Shared Object Symbol
# ........ ....... ................... ...................................................................................................................................................................................................
#
60.66% mysqld [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore
2.79% mysqld libc-2.17.so [.] __memcpy_ssse3
2.54% mysqld mysqld [.] ha_key_cmp
1.89% mysqld [vdso] [.] __vdso_clock_gettime
1.05% mysqld mysqld [.] rec_get_offsets_func
1.03% mysqld mysqld [.] row_sel_field_store_in_mysql_format_func
0.92% mysqld mysqld [.] _mi_rec_pack
0.91% mysqld [kernel.kallsyms] [k] finish_task_switch
0.90% mysqld mysqld [.] row_search_mvcc
0.86% mysqld mysqld [.] decimal2bin
0.83% mysqld mysqld [.] _mi_rec_check
….
Vzhledem k tomu, že toto může být speciální téma, do kterého se můžete začíst, doporučujeme, abyste si prohlédli tyto opravdu dobré externí blogy jako reference, základy výkonu pro profilování MySQL, hledání problémů se škálováním MySQL pomocí perf nebo se naučili, jak ladění pomocí valgrind s massif.
Efektivní způsob kontroly využití paměti MySQL
Použití ClusterControl vám ulehčí všechny nepříjemnosti, jako je procházení vašich runbooků nebo dokonce vytváření vlastních playbooků, které vám budou poskytovat zprávy. V ClusterControl máte Dashboards (pomocí SCUMM), kde můžete mít rychlý přehled o svém MySQL uzlu (uzlech). Například zobrazení hlavního panelu MySQL General,
můžete určit, jak funguje uzel MySQL,
Vidíte, že výše uvedené obrázky odhalují proměnné, které ovlivňují využití paměti MySQL. Můžete zkontrolovat, jak jsou metriky pro mezipaměti řazení, dočasné tabulky, připojená vlákna, mezipaměť dotazů nebo úložné stroje innodb buffer pool nebo klíčový buffer MyISAM.
Použití ClusterControl vám nabízí nástroj na jednom místě, kde můžete také kontrolovat spuštěné dotazy a určit ty procesy (dotazy), které mohou ovlivnit vysoké využití paměti. Příklad naleznete níže,
Zobrazení stavových proměnných MySQL je velmi snadné,
Můžete dokonce přejít na Výkon -> Stav Innodb a odhalit aktuální stav InnoDB vašich uzlů databáze. V ClusterControl je také detekován incident, pokusí se shromáždit incident a zobrazí historii jako zprávu, která vám poskytne stav InnoDB, jak je uvedeno v našem předchozím blogu o MySQL Freeze Frame.
Přehled
Odstraňování problémů a diagnostika databáze MySQL při podezření na vysoké využití paměti není tak obtížné, pokud znáte postupy a nástroje, které je třeba použít. Použití správného nástroje vám nabízí větší flexibilitu a rychlejší produktivitu při poskytování oprav nebo řešení s nadějí na lepší výsledek.