1. 错误描述

MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

Redis日志描述:

21222:C 25 Feb 03:58:01.811 * RDB: 70 MB of memory used by copy-on-write
797:M 25 Feb 03:58:01.825 * Background saving terminated with success
797:M 25 Feb 04:03:02.100 * 10 changes in 300 seconds. Saving...
797:M 25 Feb 04:03:02.101 # Can't save in background: fork: Cannot allocate memor

2. RBD持久化方式

当redis保存dump.rdb文件时:

  1. 首先,父进程fork一个子进程,此时的redis拥有父子进程
  2. 子进程将数据集写到一个临时的rdb文件中
  3. 但子进程对新的rdb写入完成后,redis会使用新文件去替换旧的rdb文件,然后将旧的删掉。

这种工作方式可以使得Redis可以从写时复制(copy-on-write)机制中获益!

3. 报错分析

Redis在dump数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为8G,这个时候也要同样分配8G的内存给child,如果内存无法负担,往往会造成redis服务器的down机或者IO负载过高,效率下降。所以这里比较优化的内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)。

内存分配策略参数

overcommit_memory参数说明: 设置内存分配策略(可选,根据服务器的实际情况进行设置) ,可选值:0、1、2。

  • 0:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
  • 1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
  • 2:表示内核允许分配超过所有物理内存和交换空间总和的内存。

3. 解决方案

  1. 忽略持久化异常,继续写入
    xxx> config set stop-writes-on-bgsave-error no
  2. 修改Linux内存分配策略
    vim /etc/sysctl.conf
    # ---
    vm.overcommit_memory = 1