mysql占用內存過多


一、計算mysql所需的內存

https://www.cnblogs.com/cheyunhua/p/9045057.html  理論有待學習

https://www.cnblogs.com/simplelogic/archive/2012/12/06/2804798.html 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
mysql used mem = key_buffer_size + query_cache_size + tmp_table_size
+ innodb_buffer_pool_size + innodb_additional_mem_pool_size
+ innodb_log_buffer_size
+ max_connections * (
read_buffer_size + read_rnd_buffer_size
+ sort_buffer_size+ join_buffer_size
+ binlog_cache_size + thread_stack
)
在mysql 中輸入如下命令,可自動計算自己的當前配置最大的內存消耗
SHOW VARIABLES LIKE ‘innodb_buffer_pool_size’;
SHOW VARIABLES LIKE ‘innodb_additional_mem_pool_size’;
SHOW VARIABLES LIKE ‘innodb_log_buffer_size’;
SHOW VARIABLES LIKE ‘thread_stack’;
SET @kilo_bytes = 1024;
SET @mega_bytes = @kilo_bytes * 1024;
SET @giga_bytes = @mega_bytes * 1024;
SET @innodb_buffer_pool_size = 2 * @giga_bytes;
SET @innodb_additional_mem_pool_size = 16 * @mega_bytes;
SET @innodb_log_buffer_size = 8 * @mega_bytes;
SET @thread_stack = 192 * @kilo_bytes;
 
SELECT
( @@key_buffer_size + @@query_cache_size + @@tmp_table_size
+ @innodb_buffer_pool_size + @innodb_additional_mem_pool_size
+ @innodb_log_buffer_size
+ @@max_connections * (
@@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size
+ @@join_buffer_size + @@binlog_cache_size + @thread_stack
) ) / @giga_bytes AS MAX_MEMORY_GB;
在mysql 中輸入如下命令,可顯示各占內存參數大小
SHOW VARIABLES LIKE ‘key_buffer_size’;
SHOW VARIABLES LIKE ‘query_cache_size’;
SHOW VARIABLES LIKE ‘tmp_table_size’;
SHOW VARIABLES LIKE ‘innodb_buffer_pool_size’;
SHOW VARIABLES LIKE ‘innodb_additional_mem_pool_size’;
SHOW VARIABLES LIKE ‘innodb_log_buffer_size’;
SHOW VARIABLES LIKE ‘read_buffer_size’;
SHOW VARIABLES LIKE ‘read_rnd_buffer_size’;
SHOW VARIABLES LIKE ‘sort_buffer_size’;
SHOW VARIABLES LIKE ‘join_buffer_size’;
SHOW VARIABLES LIKE ‘binlog_cache_size’;
SHOW VARIABLES LIKE ‘thread_stack’;

 二、查看innodb緩沖池實際使用內存

通過將緩沖池中可用的數據與InnoDB頁面(InnoDB緩沖池單位)大小相乘,可以計算InnoDB緩沖池此時正在使用的實際內存。從MySQL 5.7.6開始,GLOBAL_STATUS表中提供的信息從Performance Schema獲取。

1
2
3
4
5
6
set @ibpdata = (select variable_value from performance_schema.global_status where variable_name = 'innodb_buffer_pool_pages_data');
select @ibpdata;
set @idbpgsize = (select variable_value from performance_schema.global_status where variable_name = 'innodb_page_size');
select @idbpgsize;
set @ibpsize = @ibpdata * @idbpgsize / (1024*1024*1024);
select @ibpsize;

分配36G,實際使用34.5G,占比95%

由top命令可知mysql數據庫占服務器內存93%,即

數據庫內存:48*0.93=44.64GB

數據庫內存明細:34.55G+32+128+1600*4+200+3200=44.74GB

三、查看數據庫連接數情況

Max_connections:整個服務器的用戶限制,即mysql上限連接數 ,增加該值增加mysqld 要求的文件描述符的數量。如果服務器的並發連接請求量比較大,建議調高此值,以增加並行連接數量,當然這建立在機器能支撐的情況下,因為如果連接數越多,介於MySQL會為每個連接提供連接緩沖區,就會開銷越多的內存

Max_user_connections: 限制每個用戶的session連接個數,例如max_user_connections=1 ,那么用戶u1只能連接的session數為1,如果還有用戶u2,還是可以連接,但是連接數仍然為1,如果數據庫只有一個用戶,那Max_user_connections自然等於Max_connections。

Max_used_connections:mysql歷史響應最大連接數

Max_connect_errors:默認10,每個主機的連接請求異常中斷的最大次數

Max_connections_used_rate:最大連接數使用率,歷史最大連接數占上限連接數的85%左右,如果發現比例在10%以下,證明MySQL服務器連接數上限設置的過高了

1
2
3
4
5
6
7
show variables like '%connect%';
show global status like 'Max_used_connections';
show global status like 'Threads_connected';
--最大連接數使用率(建議85%)
Max_used_connections/max_connections
--當前連接數使用率
Threads_connected/max_connections

 

從最大連接數使用率可知max_connections設置的過高了

四、優化數據庫連接數配置

優化如下:

1
2
3
max_connections=350
max_connect_errors=50
max_user_connections=300

這里只是從連接數角度來做優化,實際場景需結合當前正在運行的sql做分析,例如可能有條sql正在做全掃,占了內存池很大空間,可以同時從show full processlist和sys.memory_global_by_current_bytes來進一步觀察,這里也是需要考慮的一個點。

五、一個實際案例

1、linux系統內存消耗主要有三個地方:

  • 進程
  • slab
  • pagecacge

free 命令查看到的是系統整體的內容使用情況,而使用 pstop 看到的內存使用情況都是以進程維度來看的,因此看不到 slabcache 和pagecache 的內存占用信息。

2、判斷應用程序是否有內存泄露問題,只根據進程的內存使用或機器的內存變化來判定都不太准確,如果單憑進程的內存變化可能會疏忽一些小對象的內存泄露問題。

同時對於機器的內存的使用也要做是否合理的判斷。對於不同語言的應用都有相應的神器可以輔助定位內存泄露問題,同時結合linux內存的監控工具進行分析, 除了 topfree還有 pmap/proc/meminfo/slabinfoslaptop等。

3、此外 page cachedentriesinodes cache,系統是會自動回收的。

可以通過以下幾種方式加速其回收,不過實際並不需要這么做。

手工清除內存 緩存

  • echo 1 > /proc/sys/vm/drop_caches 清除page cache
  • echo 2 > /proc/sys/vm/drop_caches 清除denries和inodes
  • echo 3 > /proc/sys/vm/drop_caches 清除page cache ,dentries及inodes
  • 調整 vm.vfs_cache_pressure 值大小,默認是100。值越大,dentries和inodes cache的回收速度會越快
  • 調整 vm.min_free_kbytes 值大小,該值為系統開始內存回收的閥值,越大表示系統會越早開始回收(一般情況下此值不建議調整)。

ps 大概統計下所有程序占用的總內存

1
2
3
$ echo `ps aux |awk '{mem += $6} END {print mem/1024/1024}' ` GB
 
0.595089

結果顯示所有進程占用的內存還不到 1G,實際上,因為free, ps的統計方式的差別和 Copy-on-writeShared libraries等內存優化機制的存在,這兩者的統計結果通常是不一樣的。但是一般情況下絕對不會相差十幾個G,肯定是有什么隱藏的問題,free沒有專門統計另一項緩存: Slab

Slab Allocation 是Kernel 2.2之后引入的一個內存管理機制,專門用於緩存內核的數據對象,可以理解為一個內核專用的對象池,可以提高系統性能並減少內存碎片。(Kernel 2.6.23之后,SLUB成為了默認的allocator)

查看Slab緩存

1
2
3
4
5
6
$ cat /proc/meminfo
 
# 其中,Slab相關的數據為
Slab: 154212 kB
SReclaimable: 87980 kB
SUnreclaim: 66232 kB

 SReclaimable(Linux 2.6.19+) 都是 clean 的緩存,隨時可以釋放。回到之前的內存問題,

查看服務器上Slab占用的內存:

 法一

1
2
$ cat /proc/meminfo|grep Slab
Slab: 12777668 kB

 法二

1
2
echo `cat /proc/meminfo|grep Slab|awk '{mem += $2} END {print mem/1024/1024}' ` GB
12G

 12G的Slab緩存,有意思的是free把Slab緩存統計到了 usedmemory 中,這就是之前那個問題的症結所在了。另外,還可以查看 /proc/slabinfo (或使用 slabtop 命令)來查看Slab緩存的具體使用情況。結果發現,ext3_inode_cachedentry_cache 占用了絕大部分內存。考慮到這台服務器會頻繁地用 rsync 同步大量的文件,這個結果也並不意外。

解決問題

如果問題僅僅是Slab占用了太多的內存(SReclaimable),那么通常不需要太操心,因為這根本不是個問題(如果是SUnreclaim太多且不斷增長,那么很有可能是內核有bug)。但是,如果是因為Slab占用內存太多而引起了其他的問題,建議繼續往下閱讀

清除Slab可回收緩存

通過 /proc/sys/vm/drop_caches 這個配置項,可以手動清除指定的可回收緩存(SReclaimable)

echo 2 > /proc/sys/vm/drop_caches 或者 sysctl vm.drop_caches=2

上面的命令會主動釋放 Slabclean的緩存(包括inode和dentry的緩存),然后再 free -g 一下,空閑的內存陡增了十幾個G

注意的是,手動清除緩存可能會在一段時間內降低系統性能。原則上不推薦這么做,因為如果有需要,系統會自動釋放出內存供其他程序使用。另外,手動清除Slab緩存是一個治標不治本的辦法。因為問題不在Slab,實際操作的時候發現,清除緩存一段時間后,Slab緩存很快又會反彈回去。

如果需要治本,要么搞定問題進程,要么修改系統配置,要么增加物理內存。

調整系統 vm 配置

風險預警: 調整以下系統配置可能會對系統性能造成負面影響,請仔細測試並謹慎操作

/etc/sysctl.conf 里有以下幾個對內存管理影響比較大的內核參數配置:

vm.vfs_cache_pressure

系統在進行內存回收時,會先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure 越大,每次回收時,inode cache和dentry cache所占比例越大。

vfs_cache_pressure

默認是100,該值越大inode cache和dentry cache的回收速度會越快,越小則回收越慢,為0的時候完全不回收,內存溢出(OOM!)。

vm.min_free_kbytes

系統的"保留內存"的大小,"保留內存"用於低內存狀態下的"atomic memory allocation requests"(eg. kmalloc + GFP_ATOMIC),該參數也被用於計算開始內存回收的閥值,默認在開機的時候根據當前的內存計算所得,越大則表示系統會越早開始內存回收。vm.min_free_kbytes 過大可能會導致 OOM,太小可能會導致系統出現死鎖等問題。查看默認設置:cat /proc/sys/vm/min_free_kbytes

vm.swappiness

該配置用於控制系統將內存 swap out 到交換空間的積極性,取值范圍是[0, 100]。vm.swappiness 越大,系統的交換積極性越高,默認是60, 如果為0則不會進行交換。

1
2
$ vim /etc/sysctl.conf
vm.swappiness = 1

查看默認設置:cat /proc/sys/vm/swappiness

drop_caches

默認值為0,將此值設置為1,2或3,使內核刪除頁面緩存和slab緩存的各種組合。

  • 1 系統使所有的頁面緩沖存儲器失效並釋放。
  • 2 系統釋放所有未使用的slab緩存內存。
  • 3 系統釋放所有的頁面緩存和slab緩存內存。

查看默認設置:cat /proc/sys/vm/drop_caches

注:以上參數設置是非破壞性的操作,由於臟數據不能被釋放,建議設置以上參數的值之前運行sync把內存數據寫入硬盤。在生產環境中不建議使用drop_caches釋放內存。

 

https://mp.weixin.qq.com/s/EJj3v7XaQzuuZ6LinIKaww  學習案例

 https://www.toutiao.com/i6866731337642934792/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1601656777&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=202010030039370100260771991E5BF5A8&group_id=6866731337642934792    一次生產環境MySQL服務器cpu飆升800%優化案例

分類: MySQL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM