min_free_kbytes 设置过大案例问题解析

现象:
1.zabbix提示连接不上mysql机器上的agent,无法获取服务器消息;
2.尝试ssh到这台机器,报错:
[root@dba-salt-manager ~]#  ssh  ops@10.12.32.93 -o StrictHostKeyChecking=no
kex_exchange_identification: Connection closed by remote host
Connection closed by 10.128.32.93 port 22
3. /var/log/messages报错如下:
May  5 09:25:11 mysql-account_weili-db01 kernel: Core dump to |/usr/libexec/abrt-hook-ccpp 11 0 17637 996 994 1620177911 e 17637 17637 mysql-account_weili-db01 pipe failed
May  5 09:25:11 mysql-account_weili-db01 systemd: Failed to fork: Cannot allocate memory
May  5 09:25:11 mysql-account_weili-db01 systemd: zabbix-agent.service failed to run 'stop' task: Cannot allocate memory
May  5 09:25:11 mysql-account_weili-db01 systemd: Unit zabbix-agent.service entered failed state.
May  5 09:25:11 mysql-account_weili-db01 systemd: zabbix-agent.service failed.

问题分析:
由于vm.min_free_kbytes设置的为2G太大,该参数控制系统所保留空闲内存的最低限!
设置的2G, free还有2G,但是available没有了,也就是程序已经无可用的内存了,但是由于vm.min_free_kbytes设置的过大, linux触发回收内存的阈值高(watermark [low]阈值和vm.min_free_kbytes成正比!),尽管已经没有可用的内存,但是也linux没有回收内存,所以程序就再不能分配内存了!就报前面的错了!

关于vm.min_free_kbytes在系统初始化时会根据内存大小计算一个默认值,计算规则是:
min_free_kbytes = sqrt(lowmem_kbytes * 16) = 4 * sqrt(lowmem_kbytes)(注:lowmem_kbytes即可认为是系统内存大小)
如果没有在/etc/sysctl.conf设置,那么默认计算出来的值有最小最大限制,最小为128K,最大为64M
一:设置过大会引发内存浪费,并且频繁触发oom,(前提是vm.panic_on_oom =0)
另外根据内核参数vm.panic_on_oom 设置值的不同而有不同的行为
vm.panic_on_oom=0 系统会提示oom ,并启动oom-killer杀掉占用最高内存的进程
vm.panic_on_oom =1. 系统关闭oom,不会启动oom-killer,而是会自动重启
二:如果设置过小就会 频繁导致内核进行direct reclaim(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因为是需要先回收然后再分配,所以会阻塞应用程序,带来一定的响应延迟;  设置过小会相对更频繁的触发direct reclaim,更频繁 原因在于:如果vm.min_free_kbytes设置的过小,就会导致watermark [low] 和 watermark[min]这俩值之间的差值比较小,这样的话当触发watermark [low] 的阈值后,还没有来得及回收够内存,就触发watermark[min]了,也就是更频繁触发了direct reclaim(直接回收),就可能更频繁的去导致mysql的瞬间抖动!
min_free_kbytes的主要用途是计算影响内存回收的三个参数 watermark[min/low/high]
1) watermark[high] > watermark [low] > watermark[min],各个zone各一套(每个结点的内存被分为多个块,称为zones,它表示内存中一段区域)
2)在系统空闲内存低于 watermark[low]时,开始启动内核线程kswapd进行内存回收(每个zone一个),直到该zone的空闲内存数量达到watermark[high]后停止回收。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]后,内核就会进行direct reclaim(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟,而且可能会触发系统OOM。这是因为watermark[min]以下的内存属于系统的自留内存,用以满足特殊使用,所以不会给用户态的普通申请来用;

三:最近有业务线在调大min值得时候导致物理机hang引发故障,得出一些经验和建议:
  1. 对于线上128G的内存的机器,可以考虑将min设置为512M左右。因为,太大了,可能会导致内存的浪费;当然如果只有40G的物理机,更不要考虑把min设置超过1G了,这样会导致频繁的触发内存回收;具体优化也要根据业务来看。
  2. 关键是在于调整内存的内核参数的时候! 调大的风险远大于调小的风险! 如果有人想将 vm.min_free_kbytes 调大,千万要注意当前的水位, 如果一旦调大 vm.min_free_kbytes 立刻触发direct reclaim,可能会导致机器hang住,ping的通,ssh不上,影响业务!hang住的原因是当 vm.min_free_kbytes 是512M的时候,此时 free只有1G,此时正常运行,此时如果调大vm.min_free_kbytes 到5G,将会direct reclaim失败。
解决问题:
把参数调成64M,需要注意如果你已经调大了vm.min_free_kbytes=2G了,那么你需要先把文件/etc/sysctl.conf中的值修改成vm.min_free_kbytes = 67584,然后再sysctl -p ,最后再把参数去掉!不能直接去掉vm.min_free_kbytes ,因为只有在服务器初始化的时候才会自己去计算出个值!
顺带介绍下如下三个参数:针对linux的优化,可以缓解瞬间的刷脏导致数据库的抖动!
vm.min_free_kbytes=409600;
vm.vfs_cache_pressure=200;  #默认是100,值越大,越倾向于回收cache!
vm.swappiness=40    #越低越不使用交换分区,性能越好,我们vm.swappiness = 10
注释:
vm.vfs_cache_pressure调整清理inode/dentry caches的优先级(默认为100)
降低vm.vfs_cache_pressure会导致内核倾向于保留dentry和inode缓存。将vm.vfs_cache_pressure增加到100以上会导致内核更喜欢回收dentries和inode!
vm.swappiness Linux内核参数,控制换出运行时内存的相对权重。swappiness参数值可设置范围在0到100之间。 低参数值会让内核尽量少用交换,更高参数值会使内核更多的去使用交换空间。默认值为60(参考网络资料:当剩余物理内存低于40%(40=100-60)时,开始使用交换空间)。对于大多数操作系统,设置为100可能会影响整体性能,而设置为更低值(甚至为0)则可能减少响应延迟



请使用浏览器的分享功能分享到微信等