En av nyckelfaktorerna för en presterande MySQL-databasserver är att ha bra minnesallokering och användning, speciellt när den körs i en produktionsmiljö. Men hur kan du avgöra om MySQL-användningen är optimerad? Är det rimligt att ha högt minnesutnyttjande eller kräver det finjustering? Vad händer om jag stöter på en minnesläcka?
Låt oss täcka dessa ämnen och visa de saker du kan kontrollera i MySQL för att fastställa spår av hög minnesanvändning.
Minnesallokering i MySQL
Innan vi fördjupar oss i den specifika ämnestiteln ska jag bara ge en kort information om hur MySQL använder minne. Minnet spelar en betydande resurs för hastighet och effektivitet när du hanterar samtidiga transaktioner och kör stora frågor. Varje tråd i MySQL kräver minne som används för att hantera klientanslutningar, och dessa trådar delar samma basminne. Variabler som thread_stack (stack för trådar), net_buffer_length (för anslutningsbuffert och resultatbuffert) eller med max_allowed_packet där anslutning och resultat dynamiskt kommer att förstoras upp till detta värde när det behövs, är variabler som påverkar minnesutnyttjandet. När en tråd inte längre behövs frigörs minnet som tilldelats den och returneras till systemet om inte tråden går tillbaka till trådcachen. I så fall förblir minnet allokerat. Frågekopplingar, frågecacher, sortering, tabellcache, tabelldefinitioner kräver minne i MySQL men dessa tillskrivs systemvariabler som du kan konfigurera och ställa in.
I de flesta fall är de minnesspecifika variablerna som ställts in för en konfiguration inriktade på en lagringsbaserad specifik konfiguration som MyISAM eller InnoDB. När en mysqld-instans startar inom värdsystemet, allokerar MySQL buffertar och cachar för att förbättra prestandan för databasoperationer baserat på de inställda värdena som är inställda på en specifik konfiguration. Till exempel, de vanligaste variablerna som varje DBA kommer att ställa in i InnoDB är variablerna innodb_buffer_pool_size och innodb_buffer_pool_instances som båda är relaterade till buffertpoolens minnesallokering som innehåller cachad data för InnoDB-tabeller. Det är önskvärt om du har stort minne och förväntar dig att hantera stora transaktioner genom att ställa in innodb_buffer_pool_instances för att förbättra samtidigheten genom att dela upp buffertpoolen i flera buffertpoolsinstanser.
Medan för MyISAM måste du hantera key_buffer_size för att hantera mängden minne som nyckelbufferten kommer att hantera. MyISAM allokerar också buffert för varje samtidiga tråd som innehåller en tabellstruktur, kolumnstrukturer för varje kolumn och en buffert av storleken 3 * N tilldelas (där N är den maximala radlängden, BLOB-kolumner inte medräknade). MyISAM har också en extra radbuffert för intern användning.
MySQL allokerar också minne för temporära tabeller om det inte blir för stort (bestäms av tmp_table_size och max_heap_table_size). Om du använder MEMORY-tabeller och variabeln max_heap_table_size är inställd väldigt högt, kan detta också ta ett stort minne eftersom systemvariabeln max_heap_table_size avgör hur stor en tabell kan växa, och det finns ingen konvertering till diskformat.
MySQL har också ett Performance Schema som är en funktion för att övervaka MySQL-aktiviteter på låg nivå. När detta är aktiverat, allokerar det dynamiskt minne stegvis, och skalar dess minnesanvändning till faktisk serverbelastning, istället för att allokera nödvändigt minne under serverstart. När minnet är allokerat frigörs det inte förrän servern startas om.
MySQL kan också konfigureras för att allokera stora minnesområden för dess buffertpool om du använder Linux och om kärnan är aktiverad för stöd för stora sidor, d.v.s. använder HugePages.
Vad man ska kontrollera när MySQL-minnet är högt
Kontrollera Körande frågor
Det är mycket vanligt att MySQL DBA:er först berör vad som händer med den körande MySQL-servern. De mest grundläggande procedurerna är att kontrollera processlistan, kontrollera serverstatus och kontrollera lagringsmotorns status. För att göra dessa saker behöver du i princip bara köra serien av frågor genom att logga in på MySQL. Se nedan:
För att se de pågående frågorna,
mysql> SHOW [FULL] PROCESSLIST;
Visning av den aktuella processlistan avslöjar frågor som körs aktivt eller till och med inaktiva eller vilande processer. Det är mycket viktigt och är en viktig rutin att ha ett register över frågor som körs. Som nämnts om hur MySQL allokerar minne, kommer körande frågor att använda minnesallokering och kan drastiskt orsaka prestandaproblem om de inte övervakas.
Visa MySQL-serverns statusvariabler,
mysql> SHOW SERVER STATUS\G
eller filtrera specifika variabler som
mysql> SHOW SERVER STATUS WHERE variable_name IN ('<var1>', 'var2'...);
MySQL:s statusvariabler fungerar som din statistiska information för att fånga mätdata för att avgöra hur din MySQL presterar genom att observera räknarna som ges av statusvärdena. Det finns vissa värden här som ger dig en blick som påverkar minnesutnyttjandet. Till exempel kontrollera antalet trådar, antalet tabellcacher eller buffertpoolens användning,
...
| 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 |
Visa motorns monitorstatus, till exempel InnoDB-status
mysql> SHOW ENGINE INNODB STATUS\G
InnoDB-statusen avslöjar också den aktuella statusen för transaktioner som lagringsmotorn bearbetar. Den ger dig högstorleken för en transaktion, adaptiva hashindex som avslöjar dess buffertanvändning, eller visar dig innodb buffertpoolsinformation precis som exemplet nedan:
---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]
…
En annan sak att lägga till, du kan också använda Performance Schema och sys-schema för att övervaka minnesförbrukning och användning av din MySQL-server. Som standard är de flesta instrumentering inaktiverade som standard så det finns manuella saker att göra för att använda detta.
Kontrollera efter utbyte
I vilket fall som helst, är det troligt att MySQL byter ut sitt minne till disk. Detta är ofta en mycket vanlig situation, särskilt när MySQL-servern och den underliggande hårdvaran inte är inställda optimalt parallellt med de förväntade kraven. Det finns vissa fall där efterfrågan på trafik inte har förutsetts, minnet kan växa allt mer, särskilt om dåliga frågor körs som gör att de konsumerar eller använder mycket minnesutrymme vilket orsakar försämrad prestanda eftersom data plockas på disk istället för på bufferten. För att kontrollera om det finns utbyte, kör bara freemem-kommandot eller vmstat precis som nedan,
[[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
Du kan också kontrollera med procfs och samla information som att gå till /proc/vmstat eller /proc/meminfo.
Använda Perf, gdb och Valgrind med Massif
Att använda verktyg som perf, gdb och valgrind hjälper dig att gräva i en mer avancerad metod för att bestämma MySQL-minnesanvändning. Det finns tillfällen då ett intressant resultat blir ett mysterium att lösa minnesförbrukning som leder till din förvirring i MySQL. Detta leder till behovet av att ha mer skepsis och att använda dessa verktyg hjälper dig att undersöka hur MySQL använder hanteringsminne från att allokera det till att använda det för att bearbeta transaktioner eller processer. Detta är användbart till exempel om du observerar att MySQL beter sig onormalt som kan orsaka dålig konfiguration eller kan leda till upptäckt av minnesläckor.
Om du till exempel använder perf i MySQL avslöjar mer information i en rapport på systemnivå:
[[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
….
Eftersom det här kan vara ett speciellt ämne att gräva i, föreslår vi att du tittar på dessa riktigt bra externa bloggar som dina referenser, förf. Grunder för MySQL-profilering, Hitta MySQL-skalningsproblem med hjälp av perf, eller lär dig hur du felsök med valgrind med massiv.
Effektivt sätt att kontrollera MySQL-minnesutnyttjandet
Att använda ClusterControl lindrar alla krångelrutiner som att gå igenom dina runbooks eller till och med skapa dina egna playbooks som skulle leverera rapporter åt dig. I ClusterControl har du Dashboards (med hjälp av SCUMM) där du kan få en snabb överblick över dina MySQL-noder. Till exempel genom att titta på MySQL General dashboard,
du kan bestämma hur MySQL-noden fungerar,
Du ser att bilderna ovan avslöjar variabler som påverkar MySQL-minnesanvändningen. Du kan kontrollera hur mätvärdena för sortering av cachar, temporära tabeller, anslutna trådar, frågecache eller lagringsmotorer innodb buffertpool eller MyISAMs nyckelbuffert.
Användning av ClusterControl ger dig ett verktyg i ett enda tillfälle där du också kan kontrollera frågor som körs för att fastställa vilka processer (frågor) som kan påverka hög minnesanvändning. Se nedan för ett exempel,
Att visa statusvariablerna för MySQL är ganska enkelt,
Du kan även gå till Prestanda -> Innodb Status för att avslöja aktuell InnoDB-status för dina databasnoder. I ClusterControl upptäcks också en incident, den försöker samla in incidenten och visar historiken som en rapport som ger dig InnoDB-status som visas i vår tidigare blogg om MySQL Freeze Frame.
Sammanfattning
Att felsöka och diagnostisera din MySQL-databas när du misstänker hög minnesanvändning är inte så svårt så länge du känner till procedurerna och verktygen som ska användas. Att använda rätt verktyg ger dig mer flexibilitet och snabbare produktivitet för att leverera korrigeringar eller lösningar med chans till bättre resultat.