Redis 写磁盘出错 Cannot allocate memory

故障简介

早上查看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

推荐阅读更多精彩内容

  • 安全性 设置客户端连接后进行任何其他指令前需要使用的密码。 警告:因为redis 速度相当快,所以在一台比较好的服...
    OzanShareing阅读 896评论 1 8
  • 1.1 资料 ,最好的入门小册子,可以先于一切文档之前看,免费。 作者Antirez的博客,Antirez维护的R...
    JefferyLcm阅读 15,604评论 1 52
  • 摘自http://xiaoh.me/2016/06/30/redis-advanced/ 排序 redis支持对l...
    鸵鸟要抬头阅读 64,998评论 1 3
  • 转载:Redis性能问题排查解决手册(七) 阅读目录: 性能相关的数据指标 内存使用率used_memory 命令...
    meng_philip123阅读 2,662评论 0 30
  • Redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。Redis ...
    drfung阅读 460评论 0 10