linux下redis执行bgsave时,报overcommit_memory错误问题
现象
一台机器如果内存用完,在进行bgsave时,可能会报错。错误信息大概如下:
[1946] 23 Mar 15:21:02.308 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
原因
当执行redis的bgsave命令时,redis会fork一个进程把redis中的内存数据写入磁盘。这样的好处是,copy on write,有效的节省了内存占用。但是,bgsave时,如果有数据变更,一样需要申请内存。当申请内存时,如果发现内存不够,可能就会报上面的错误。
内核参数overcommit_memory
参数vm.overcommit_memory控制着linux的内存分配策略。
这个参数有三个值: 0 1 2
0 表示启发式处理。会尽量减少swap的使用,root可以分配比一般用户略多的内存。默认值。
1 表示一直允许overcommit。一般用户科学计算。
2 表示不允许超过CommitLimit值。根据vm.overcommit_ratio定义的值,允许分配超出物理内存加上交换内存的请求。vm.overcommit_ratio参数是一个百分比,加上内存量决定内存可以超量分配多少内存。例如,vm.overcommit_ratio值为50,而内存有1GB,那么这意味着在内存分配请求失败前,加上交换内存,内存将允许高达1.5GB的内存分配请求。
之所以允许申请大于内存的malloc,其中一个原因是,malloc后,并不一定马上使用。
相关英文文档阅读
overcommit_memory
Overcommit and OOM
设置方法
很简单,按提示的操作(将vm.overcommit_memory 设为1)即可:
有三种方式修改内核参数,但要有root权限:
(1)编辑/etc/sysctl.conf ,改vm.overcommit_memory=1,然后sysctl -p 使配置文件生效
(2)sysctl vm.overcommit_memory=1
(3)echo 1 > /proc/sys/vm/overcommit_memory
设置完后,可以通过 sysctl -n vm.overcommit_memory 验证设置是否生效。
延伸阅读
OOM
当linux发现内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。
当oom-killer发生时,linux会选择杀死哪些进程?选择进程的函数是oom_badness函数(在mm/oom_kill.c中),该函数会计算每个进程的点数(0~1000)。点数越高,这个进程越有可能被杀死。每个进程的点数跟oom_score_adj有关,而且oom_score_adj可以被设置(-1000最低,1000最高)。
查看内存总量和已用内存
grep -i commit /proc/meminfo
看到CommitLimit和Committed_As参数。
CommitLimit是一个内存分配上限,CommitLimit = 物理内存 * overcommit_ratio(默认50,即50%) + swap大小
Committed_As是已经分配的内存大小。