最近生产环境遇到一个很奇怪的问题,系统内存32G,redis使用8G左右,剩余的内存都被系统cache使用,从表面上看系统可用内存有20G左右。可是系统运行过程当中,redis时不时会用到swap,并且在AOF重写期间swap使用量更是突增(mem_fragmentation_ratio 值低于1)致使redis性能严重降低。html
而后搜索网上的各类资料,调整redis参数,主要作了如下几个部分:redis
一、调整/ proc/sys/vm/swappinessapp
二、调整 no-appendfsync-on-rewrite yes,减小AOF重写时的IO争用性能
三、添加最大内存限制 maxmemory 24gbspa
四、手动释放cache echo 1 > /proc/sys/vm/drop_caches,释放后系统过一段时间又会占满htm
以上操做完成后,仍然没有效果。blog
而后采起临时手段,在备机上将swap分区禁用,暂时解决问题,主机仍然保留现场继续查问题(这期间调整auto-aof-rewrite-percentage 300,减小重写频率)。进程
最后查看到关于NUMA的资料,结合生成环境系统分析,确认存在内存分配策略问题的这种可能性。内存
大概的缘由以下:资源
在多核CPU的环境下,numa采用对CPU和内存分组的方式管理资源,每一个CPU分组对应1个内存分组,在默认策略状况下,CPU使用本身组内的内存空间,若新进程申请内存时,没有足够的空闲内存,则可能用到swap空间,而不去其余CPU组申请内存。
这里有一个简单的验证方法:
一、手工释放cache echo 1 > /proc/sys/vm/drop_caches
二、numactl --hardware 查看每一个CPU分组中空余内存大小是否基本一致,若出现某个组free很小,其余组明显大于该组,则多是内存策略分配引发的问题。
注意:这里看到的free是不含cache部分占用的内存,因此要先释放一下cache
解决办法:
在redis启动命令前面加上 numactl --interleave=all ,表示采用轮询的方式到各组申请内存,这样重启redis后问题解决,改善的点以下:
一、redis AOF重写时再也不使用到swap,重写基本在1分钟左右完成(故障期间长达30分钟)
二、sar -b 查看IO,每秒写入量和tps均有明细降低
三、redis内存碎片指数 mem_fragmentation_ratio 一直保持大于1
NUMA参考资料:http://www.cnblogs.com/xueqiuqiu/articles/9282903.html