Jednym z kluczowych czynników wydajnego serwera bazy danych MySQL jest dobra alokacja i wykorzystanie pamięci, zwłaszcza podczas uruchamiania go w środowisku produkcyjnym. Ale jak określić, czy wykorzystanie MySQL jest zoptymalizowane? Czy to rozsądne, aby mieć wysokie wykorzystanie pamięci, czy wymaga to dostrojenia? Co się stanie, jeśli napotkam wyciek pamięci?
Omówmy te tematy i pokażmy, co można sprawdzić w MySQL, aby określić ślady wysokiego wykorzystania pamięci.
Alokacja pamięci w MySQL
Zanim zagłębimy się w konkretny tytuł tematu, przedstawię tylko krótką informację o tym, jak MySQL wykorzystuje pamięć. Pamięć odgrywa znaczący zasób szybkości i wydajności podczas obsługi współbieżnych transakcji i wykonywania dużych zapytań. Każdy wątek w MySQL wymaga pamięci, która służy do zarządzania połączeniami klientów, a te wątki współdzielą tę samą pamięć podstawową. Zmienne, takie jak thread_stack (stos dla wątków), net_buffer_length (dla bufora połączenia i bufora wyniku) lub z max_allowed_packet, gdzie połączenie i wynik będą dynamicznie powiększać się do tej wartości w razie potrzeby, są zmiennymi, które mają wpływ na wykorzystanie pamięci. Gdy wątek nie jest już potrzebny, przydzielona mu pamięć jest zwalniana i zwracana do systemu, chyba że wątek wraca do pamięci podręcznej wątków. W takim przypadku pamięć pozostaje przydzielona. Sprzężenia zapytań, pamięci podręczne zapytań, sortowanie, pamięć podręczna tabel, definicje tabel wymagają pamięci w MySQL, ale są one przypisywane zmiennym systemowym, które można konfigurować i ustawiać.
W większości przypadków zmienne specyficzne dla pamięci ustawione dla konfiguracji są ukierunkowane na konfigurację opartą na pamięci masowej, taką jak MyISAM lub InnoDB. Kiedy instancja mysqld pojawia się w systemie hosta, MySQL przydziela bufory i pamięci podręczne, aby poprawić wydajność operacji bazy danych w oparciu o wartości ustawione w określonej konfiguracji. Na przykład najczęstszymi zmiennymi, które każdy DBA ustawi w InnoDB, są zmienne innodb_buffer_pool_size i innodb_buffer_pool_instances, które są powiązane z alokacją pamięci puli buforów, która przechowuje buforowane dane dla tabel InnoDB. Jest to pożądane, jeśli masz dużą pamięć i oczekujesz obsługi dużych transakcji, ustawiając innodb_buffer_pool_instances, aby poprawić współbieżność poprzez podzielenie puli buforów na wiele instancji puli buforów.
Podczas gdy dla MyISAM, musisz poradzić sobie z key_buffer_size, aby obsłużyć ilość pamięci, którą obsłuży bufor klucza. MyISAM również alokuje bufor dla każdego współbieżnego wątku, który zawiera strukturę tabeli, struktury kolumn dla każdej kolumny i bufor o rozmiarze 3 * N są przydzielane (gdzie N jest maksymalną długością wiersza, nie licząc kolumn BLOB). MyISAM utrzymuje również jeden dodatkowy bufor wierszy do użytku wewnętrznego.
MySQL alokuje również pamięć dla tabel tymczasowych, chyba że stanie się zbyt duża (określona przez tmp_table_size i max_heap_table_size). Jeśli używasz tabel MEMORY, a zmienna max_heap_table_size jest ustawiona na bardzo wysoką, może to również zająć dużo pamięci, ponieważ zmienna systemowa max_heap_table_size określa, jak duża może się rozrosnąć tabela i nie ma konwersji na format na dysku.
MySQL posiada również schemat wydajności, który jest funkcją monitorowania aktywności MySQL na niskim poziomie. Po włączeniu dynamicznie przydziela pamięć przyrostowo, skalując jej wykorzystanie do rzeczywistego obciążenia serwera, zamiast przydzielać wymaganą pamięć podczas uruchamiania serwera. Po przydzieleniu pamięci nie jest ona zwalniana do czasu ponownego uruchomienia serwera.
MySQL można również skonfigurować do przydzielania dużych obszarów pamięci dla swojej puli buforów, jeśli używasz Linuksa i jeśli jądro jest włączone do obsługi dużych stron, tj. Używając HugePages.
Co należy sprawdzić, gdy pamięć MySQL jest wysoka
Sprawdź uruchomione zapytania
Bardzo często administratorzy baz danych MySQL najpierw dowiadują się, co się dzieje z uruchomionym serwerem MySQL. Najbardziej podstawowe procedury to sprawdzenie listy procesów, sprawdzenie stanu serwera i sprawdzenie stanu silnika pamięci masowej. Aby to zrobić, wystarczy uruchomić serię zapytań, logując się do MySQL. Zobacz poniżej:
Aby wyświetlić uruchomione zapytania,
mysql> SHOW [FULL] PROCESSLIST;
Wyświetlenie bieżącej listy procesów ujawnia zapytania, które są aktywne, a nawet nieaktywne lub uśpione. Posiadanie rejestru uruchomionych zapytań jest bardzo ważne i ważne. Jak wspomniano, w jaki sposób MySQL alokuje pamięć, uruchamianie zapytań będzie wykorzystywać alokację pamięci i może drastycznie powodować problemy z wydajnością, jeśli nie jest monitorowane.
Wyświetl zmienne stanu serwera MySQL,
mysql> SHOW SERVER STATUS\G
lub filtruj określone zmienne, takie jak
mysql> SHOW SERVER STATUS WHERE variable_name IN ('<var1>', 'var2'...);
Zmienne stanu MySQL służą jako informacje statystyczne do pobierania danych metrycznych w celu określenia, jak działa MySQL, obserwując liczniki podane przez wartości stanu. Istnieją tutaj pewne wartości, które dają spojrzenie, które ma wpływ na wykorzystanie pamięci. Na przykład sprawdzenie liczby wątków, liczby pamięci podręcznych tabel lub wykorzystania puli buforów,
...
| 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 |
Wyświetl stan monitora silnika, na przykład stan InnoDB
mysql> SHOW ENGINE INNODB STATUS\G
Status InnoDB ujawnia również aktualny stan transakcji przetwarzanych przez silnik pamięci masowej. Podaje rozmiar sterty transakcji, adaptacyjne indeksy mieszające ujawniające wykorzystanie bufora lub pokazuje informacje o puli buforów innodb, tak jak w poniższym przykładzie:
---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]
…
Kolejna rzecz do dodania, możesz również użyć schematu wydajności i schematu sys do monitorowania zużycia i wykorzystania pamięci przez serwer MySQL. Domyślnie większość oprzyrządowania jest domyślnie wyłączona, więc istnieją ręczne czynności, aby z tego skorzystać.
Sprawdź zamianę
Tak czy inaczej, prawdopodobnie MySQL wymienia pamięć na dysk. Jest to często bardzo powszechna sytuacja, zwłaszcza gdy serwer MySQL i bazowy sprzęt nie są ustawione optymalnie równolegle do oczekiwanych wymagań. Istnieją pewne przypadki, w których nie przewidziano zapotrzebowania na ruch, pamięć może rosnąć coraz bardziej, zwłaszcza jeśli uruchamiane są złe zapytania powodujące zużywanie lub wykorzystywanie dużej ilości miejsca w pamięci, powodując pogorszenie wydajności, ponieważ dane są pobierane z dysku, a nie z bufora. Aby sprawdzić zamianę, po prostu uruchom polecenie freemem lub vmstat, tak jak poniżej,
[[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
Możesz również sprawdzić za pomocą procfs i zebrać informacje, takie jak przejście do /proc/vmstat lub /proc/meminfo.
Korzystanie z Perf, gdb i Valgrind z Massif
Korzystanie z narzędzi takich jak perf, gdb i valgrind pomaga zagłębić się w bardziej zaawansowaną metodę określania wykorzystania pamięci MySQL. Czasami interesujący wynik staje się tajemnicą rozwiązania problemu zużycia pamięci, który prowadzi do oszołomienia w MySQL. To wymaga większego sceptycyzmu, a korzystanie z tych narzędzi pomaga zbadać, w jaki sposób MySQL wykorzystuje obsługę pamięci, od przydzielania jej do wykorzystywania do przetwarzania transakcji lub procesów. Jest to przydatne, na przykład, jeśli obserwujesz, że MySQL zachowuje się nienormalnie, co może powodować złą konfigurację lub może prowadzić do stwierdzenia wycieków pamięci.
Na przykład użycie perf w MySQL ujawnia więcej informacji w raporcie na poziomie systemu:
[[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
….
Ponieważ może to być specjalny temat do zagłębienia się, sugerujemy, abyś zajrzał do tych naprawdę dobrych zewnętrznych blogów jako referencji, perf Podstawy profilowania MySQL, Znajdowanie problemów ze skalowaniem MySQL debuguj za pomocą valgrind z masywem.
Wydajny sposób sprawdzania wykorzystania pamięci MySQL
Korzystanie z ClusterControl eliminuje wszelkie uciążliwe procedury, takie jak przeglądanie elementów Runbook, a nawet tworzenie własnych podręczników, które dostarczają raporty. W ClusterControl masz pulpity nawigacyjne (przy użyciu SCUMM), w których możesz uzyskać szybki przegląd swoich węzłów MySQL. Na przykład przeglądanie pulpitu nawigacyjnego MySQL General,
możesz określić, jak działa węzeł MySQL,
Widać, że powyższe obrazy pokazują zmienne, które wpływają na wykorzystanie pamięci MySQL. Możesz sprawdzić, jak metryki sortowania pamięci podręcznych, tabel tymczasowych, podłączonych wątków, pamięci podręcznej zapytań lub silników pamięci masowej w puli buforów innodb lub bufora kluczy MyISAM.
Korzystanie z ClusterControl oferuje kompleksowe narzędzie, za pomocą którego można również sprawdzać uruchomione zapytania w celu określenia tych procesów (zapytań), które mogą mieć wpływ na wysokie wykorzystanie pamięci. Zobacz przykład poniżej,
Wyświetlanie zmiennych stanu MySQL jest dość łatwe,
Możesz nawet przejść do Wydajność -> Stan Innodb, aby wyświetlić aktualny stan InnoDB węzłów bazy danych. Ponadto w ClusterControl wykryty zostanie incydent, który spróbuje zebrać incydent i wyświetli historię jako raport, który zapewnia status InnoDB, jak pokazano w naszym poprzednim blogu o MySQL Freeze Frame.
Podsumowanie
Rozwiązywanie problemów i diagnozowanie bazy danych MySQL w przypadku podejrzenia wysokiego wykorzystania pamięci nie jest trudne, o ile znasz procedury i narzędzia, których należy użyć. Korzystanie z odpowiedniego narzędzia zapewnia większą elastyczność i szybszą produktywność w celu dostarczania poprawek lub rozwiązań z szansą na lepszy wynik.