故障简介
早上查看Redis日志的时候发现Redis一直在报错
[1524] 24 Mar 10:00:56.037 * 1 changes in 900 seconds. Saving...
[1524] 24 Mar 10:00:56.037 # Can't save in background: fork: Cannot allocate memory
Redis数据回写机制
数据回写分同步和异步两种方式
- 同步回写(
SAVE
), 主进程直接向磁盘回写数据. 在数据量大的情况下会导致系统假死很长时间 - 异步回写(
BGSAVE
), 主进程fork后, 复制自身并通过这个新的进程回写磁盘, 回写结束后新进程自行关闭.
由于 BGSAVE
不需要主进程阻塞, 系统也不会假死, 一般会采用 BGSAVE
来实现数据回写.
故障分析
在小内存的进程上做fork, 不需要太多资源. 但当这个进程的内存空间以G为单位时, fork就成为一件很恐怖的操作.
在16G内存的足迹上fork 14G的进程, 系统肯定Cannot allocate memory
.
主机的Redis 改动的越频繁 fork进程也越频繁, 所以一直在Cannot allocate memory
解决方案
直接修改内核参数 vm.overcommit_memory = 1, Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。
vm.overcommit_memory = 1,直接放行
vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
vm.overcommit_memory = 2:则会比较进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行。
源码如下:
/* 在/etc/sysctl.conf文件里面加入或者直接删除也可以,因为它缺省值就是 */
sudo echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sudo sysctl -p