Salah satu faktor kunci dari server database MySQL yang berkinerja baik adalah memiliki alokasi dan pemanfaatan memori yang baik, terutama saat menjalankannya di lingkungan produksi. Tapi bagaimana Anda bisa menentukan apakah pemanfaatan MySQL dioptimalkan? Apakah masuk akal untuk memiliki pemanfaatan memori yang tinggi atau apakah itu memerlukan penyetelan yang baik? Bagaimana jika saya menghadapi kebocoran memori?
Mari kita bahas topik ini dan tunjukkan hal-hal yang dapat Anda periksa di MySQL untuk menentukan jejak penggunaan memori yang tinggi.
Alokasi Memori di MySQL
Sebelum kita membahas judul subjek tertentu, saya hanya akan memberikan informasi singkat tentang bagaimana MySQL menggunakan memori. Memori memainkan sumber daya yang signifikan untuk kecepatan dan efisiensi saat menangani transaksi bersamaan dan menjalankan kueri besar. Setiap utas di MySQL membutuhkan memori yang digunakan untuk mengelola koneksi klien, dan utas ini berbagi memori dasar yang sama. Variabel seperti thread_stack (tumpukan untuk utas), net_buffer_length (untuk buffer koneksi dan buffer hasil), atau dengan max_allowed_packet di mana koneksi dan hasil akan secara dinamis memperbesar hingga nilai ini bila diperlukan, adalah variabel yang memengaruhi penggunaan memori. Ketika utas tidak lagi diperlukan, memori yang dialokasikan untuk itu dilepaskan dan dikembalikan ke sistem kecuali utas kembali ke cache utas. Dalam hal ini, memori tetap dialokasikan. Penggabungan kueri, cache kueri, pengurutan, cache tabel, definisi tabel memang memerlukan memori di MySQL tetapi ini dikaitkan dengan variabel sistem yang dapat Anda konfigurasi dan atur.
Dalam kebanyakan kasus, variabel khusus memori yang ditetapkan untuk konfigurasi ditargetkan pada konfigurasi khusus berbasis penyimpanan seperti MyISAM atau InnoDB. Ketika instance mysqld muncul di dalam sistem host, MySQL mengalokasikan buffer dan cache untuk meningkatkan kinerja operasi database berdasarkan nilai yang ditetapkan pada konfigurasi tertentu. Misalnya, variabel paling umum yang akan ditetapkan setiap DBA di InnoDB adalah variabel innodb_buffer_pool_size dan innodb_buffer_pool_instances yang keduanya terkait dengan alokasi memori kumpulan buffer yang menyimpan data cache untuk tabel InnoDB. Sebaiknya jika Anda memiliki memori besar dan mengharapkan untuk menangani transaksi besar dengan mengatur innodb_buffer_pool_instances untuk meningkatkan konkurensi dengan membagi kumpulan buffer menjadi beberapa contoh kumpulan buffer.
Sementara untuk MyISAM, Anda harus berurusan dengan key_buffer_size untuk menangani jumlah memori yang akan ditangani oleh buffer kunci. MyISAM juga mengalokasikan buffer untuk setiap utas bersamaan yang berisi struktur tabel, struktur kolom untuk setiap kolom, dan buffer ukuran 3 * N dialokasikan (di mana N adalah panjang baris maksimum, tidak termasuk kolom BLOB). MyISAM juga mempertahankan satu buffer baris tambahan untuk penggunaan internal.
MySQL juga mengalokasikan memori untuk tabel sementara kecuali jika menjadi terlalu besar (ditentukan oleh tmp_table_size dan max_heap_table_size). Jika Anda menggunakan tabel MEMORY dan variabel max_heap_table_size disetel sangat tinggi, ini juga dapat mengambil memori yang besar karena variabel sistem max_heap_table_size menentukan seberapa besar tabel dapat berkembang, dan tidak ada konversi ke format di disk.
MySQL juga memiliki Performance Schema yang merupakan fitur untuk memonitor aktivitas MySQL pada level rendah. Setelah ini diaktifkan, ia secara dinamis mengalokasikan memori secara bertahap, menskalakan penggunaan memorinya ke beban server yang sebenarnya, alih-alih mengalokasikan memori yang diperlukan selama startup server. Setelah memori dialokasikan, itu tidak dibebaskan sampai server di-restart.
MySQL juga dapat dikonfigurasi untuk mengalokasikan area memori yang besar untuk kumpulan buffernya jika menggunakan Linux dan jika kernel diaktifkan untuk dukungan halaman yang besar, yaitu menggunakan HugePages.
Yang Harus Diperiksa Setelah Memori MySQL Tinggi
Periksa Kueri yang Berjalan
Sangat umum bagi DBA MySQL untuk menyentuh dasar terlebih dahulu apa yang terjadi dengan server MySQL yang sedang berjalan. Prosedur paling dasar adalah memeriksa daftar proses, memeriksa status server, dan memeriksa status mesin penyimpanan. Untuk melakukan hal-hal tersebut, pada dasarnya Anda tinggal menjalankan rangkaian query dengan login ke MySQL. Lihat di bawah:
Untuk melihat kueri yang sedang berjalan,
mysql> SHOW [FULL] PROCESSLIST;
Melihat daftar proses saat ini mengungkapkan kueri yang sedang berjalan secara aktif atau bahkan proses idle atau tidur. Sangat penting dan merupakan rutinitas yang signifikan untuk memiliki catatan kueri yang sedang berjalan. Sebagaimana disebutkan tentang cara MySQL mengalokasikan memori, menjalankan kueri akan menggunakan alokasi memori dan secara drastis dapat menyebabkan masalah kinerja jika tidak dipantau.
Melihat variabel status server MySQL,
mysql> SHOW SERVER STATUS\G
atau filter variabel tertentu seperti
mysql> SHOW SERVER STATUS WHERE variable_name IN ('<var1>', 'var2'...);
Variabel status MySQL berfungsi sebagai informasi statistik Anda untuk mengambil data metrik guna menentukan kinerja MySQL Anda dengan mengamati penghitung yang diberikan oleh nilai status. Ada nilai tertentu di sini yang memberi Anda pandangan yang memengaruhi penggunaan memori. Misalnya, memeriksa jumlah utas, jumlah cache tabel, atau penggunaan kumpulan buffer,
...
| 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 |
Melihat status monitor mesin, misalnya, status InnoDB
mysql> SHOW ENGINE INNODB STATUS\G
Status InnoDB juga mengungkapkan status transaksi saat ini yang sedang diproses oleh mesin penyimpanan. Ini memberi Anda ukuran tumpukan transaksi, indeks hash adaptif yang mengungkapkan penggunaan buffernya, atau menampilkan informasi kumpulan buffer innodb seperti contoh di bawah ini:
---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]
…
Hal lain untuk ditambahkan, Anda juga dapat menggunakan Skema Kinerja dan skema sistem untuk memantau konsumsi dan penggunaan memori oleh server MySQL Anda. Secara default, sebagian besar instrumentasi dinonaktifkan secara default sehingga ada hal-hal manual yang harus dilakukan untuk menggunakan ini.
Periksa Swappiness
Bagaimanapun, kemungkinan MySQL menukar memorinya ke disk. Ini seringkali merupakan situasi yang sangat umum terutama ketika server MySQL dan perangkat keras yang mendasarinya tidak diatur secara optimal secara paralel dengan persyaratan yang diharapkan. Ada kasus tertentu di mana permintaan lalu lintas belum diantisipasi, memori dapat bertambah terutama jika kueri buruk dijalankan yang menyebabkan penggunaan atau penggunaan banyak ruang memori yang menyebabkan penurunan kinerja karena data diambil di disk alih-alih di buffer. Untuk memeriksa swappiness, jalankan saja perintah freemem atau vmstat seperti di bawah ini,
[[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
Anda juga dapat memeriksa menggunakan procfs dan mengumpulkan informasi seperti membuka /proc/vmstat atau /proc/meminfo.
Menggunakan Perf, gdb, dan Valgrind dengan Massif
Menggunakan alat seperti perf, gdb, dan valgrind membantu Anda menggali metode yang lebih maju untuk menentukan penggunaan memori MySQL. Ada kalanya hasil yang menarik menjadi misteri pemecahan konsumsi memori yang menyebabkan kebingungan Anda di MySQL. Hal ini menyebabkan kebutuhan untuk lebih skeptis dan menggunakan alat ini membantu Anda menyelidiki bagaimana MySQL menggunakan memori penanganan mulai dari mengalokasikannya hingga menggunakannya untuk memproses transaksi atau proses. Ini berguna misalnya jika Anda mengamati MySQL berperilaku tidak normal yang dapat menyebabkan konfigurasi yang buruk atau dapat menyebabkan temuan kebocoran memori.
Misalnya, menggunakan perf di MySQL mengungkapkan lebih banyak informasi dalam laporan tingkat sistem:
[[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
….
Karena ini bisa menjadi topik khusus untuk digali, kami sarankan Anda melihat ke blog eksternal yang sangat bagus ini sebagai referensi Anda, dasar-dasar perf untuk Profil MySQL, Menemukan Masalah Penskalaan MySQL Menggunakan perf, atau pelajari cara debug menggunakan valgrind dengan massif.
Cara Efisien Untuk Memeriksa Penggunaan Memori MySQL
Menggunakan ClusterControl mengurangi rutinitas yang merepotkan seperti menelusuri runbook Anda atau bahkan membuat playbook Anda sendiri yang akan mengirimkan laporan untuk Anda. Di ClusterControl, Anda memiliki Dasbor (menggunakan SCUMM) di mana Anda dapat memiliki gambaran singkat tentang node MySQL Anda. Misalnya, melihat dasbor Umum MySQL,
Anda dapat menentukan kinerja node MySQL,
Anda melihat bahwa gambar di atas mengungkapkan variabel yang memengaruhi penggunaan memori MySQL. Anda dapat memeriksa bagaimana metrik untuk cache pengurutan, tabel sementara, utas terhubung, cache kueri, atau mesin penyimpanan innodb buffer pool atau buffer kunci MyISAM.
Menggunakan ClusterControl menawarkan alat utilitas lengkap tempat Anda juga dapat memeriksa kueri yang berjalan untuk menentukan proses (kueri) yang dapat memengaruhi penggunaan memori yang tinggi. Lihat di bawah untuk contoh,
Melihat variabel status MySQL sangat mudah,
Anda bahkan dapat pergi ke Performance -> Status Innodb juga untuk mengungkapkan status InnoDB saat ini dari node database Anda. Selain itu, di ClusterControl, sebuah insiden terdeteksi, ia akan mencoba mengumpulkan insiden dan menampilkan riwayat sebagai laporan yang memberi Anda status InnoDB seperti yang ditunjukkan di blog kami sebelumnya tentang MySQL Freeze Frame.
Ringkasan
Memecahkan masalah dan mendiagnosis database MySQL Anda saat mencurigai penggunaan memori yang tinggi tidaklah sulit selama Anda mengetahui prosedur dan alat yang digunakan. Menggunakan alat yang tepat memberi Anda lebih banyak fleksibilitas dan produktivitas lebih cepat untuk memberikan perbaikan atau solusi dengan peluang hasil yang lebih besar.