一、現象
可能大家都遇到過這么一種現象。MySQL占用着內存不釋放,然后還時不時的一點點增加。
二、問題排查
結合官方文檔 https://dev.mysql.com/doc/refman/5.7/en/memory-use.html 和 percona文檔 https://www.percona.com/blog/2018/06/28/what-to-do-when-mysql-runs-out-of-memory-troubleshooting-guide/
得出以下MySQL占用內存的計算方法
--查看每個線程占用多少內存,然后乘以正在運行的線程(也就是排查sleep的)。 SELECT ( ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size + @@thread_stack + @@max_allowed_packet + @@net_buffer_length ) ) / (1024*1024) AS MEMORY_MB; --查看MySQL全局占用多少內存 select (@@innodb_buffer_pool_size +@@innodb_log_buffer_size +@@key_buffer_size) / 1024 /1024 AS MEMORY_MB; --查看performance_schema占用多少內存 SELECT SUBSTRING_INDEX(event_name,'/',2) AS code_area, sys.format_bytes(SUM(current_alloc)) AS current_alloc FROM sys.x$memory_global_by_current_bytes GROUP BY SUBSTRING_INDEX(event_name,'/',2) ORDER BY SUM(current_alloc) DESC; --查看 memory 存儲引擎占用多少內存 select sum(max_data_length)/1024/1024 as MEMORY_MB from tables where engine='memory';
再把上面的結果相加,就是MySQL當前占用的內存大小。但問題是算出來的結果比實際的小了很多。但如果拿歷史最大連接數去算的話,結果是差不多的。所以,就在懷疑,MySQL是否有一個內存的“高水位“。因此帶着疑問做了以下實驗
三、實驗
操作系統:centos 7.4
MySQL:percona 5.7.23
內存:32G
innodb_buffer_pool_size:8G
3.1 首先重啟MySQL,釋放掉內存,重啟后,innodb_buffer_pool 中有 free_page,這時候,使用 sysbench 生成 8G 數據。全表掃描 sbtest1,把innodb_buffer_pool 占滿,觀察當前MySQL占用的內存
--全表掃描sbtest1 select count(*) from (select * from sbtest1) a; --查看innodb_buffer_pool情況 select sum(POOL_SIZE),sum(free_buffers),sum(DATABASE_PAGES) from INNODB_BUFFER_POOL_STATS; +----------------+-------------------+---------------------+ | sum(POOL_SIZE) | sum(free_buffers) | sum(DATABASE_PAGES) | +----------------+-------------------+---------------------+ | 524224 | 6537 | 517687 | +----------------+-------------------+---------------------+
因為我設置 innodb_buffer_pool_instance = 8,innodb_lru_scan_depth = 1024。所以 free_page 最大會剩余 8192 個 buffer。
top 觀察到當前 MySQL 占用 8.8G左右
3.2 調整線程。thread 增加到50個,然后觀察內存。
0.010 * 1024 = 10.24G 左右。內存從 8.8G 增加到 10.24G,等到查詢結束,MySQL內存並沒有釋放回 8.8G
3.3 把 thread 調整到 10個,觀察內存
內存並沒有增加
3.4 把 thread 調整到 100個,觀察內存
0.012 * 1024 = 12.28(G) 左右
四、結論
從目前的實驗結果來看,mysql 會把內存占用不釋放,像是有一個歷史高水位在那里,比如說,我歷史跑過最大連接數 50 個,mysqld占用了 10.24G內存,接下來跑 10個連接數的時候,則內存不會增加。最后跑了100個連接數,內存又增加到12.28G。然后就一直保持在12.28G。
該結論純屬由實驗得出的,可能有錯誤,偏差的地方。如果有朋友覺得結論有錯誤,或者覺得以偏概全,可以聯系 QQ:505701092。歡迎一起討論或者指正,謝謝!