代码和日志文件中出现的报错信息:

经过排查发现各个项目都是redis(端口:4602)出现报错,报错信息一致:'MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.'

大概意思:MISCONF Redis配置为保存RDB快照,但当前无法持久保存在磁盘上。 禁用了可能修改数据集的命令,因为此实例配置为在RDB快照失败时在写入过程中报告错误(stop-writes-on-bgsave-error选项)。 请检查Redis日志以获取有关RDB错误的详细信息。

redis出现的现象:redis(端口:4602)储存的内容被擦除。

可能的原因:由于无法持久保存到磁盘,导致redis运行时,没有权限修改“dump.rdb”的权限(dump.rdb是redis的快照,它会在一个特定的间隔保存那个时间点的一个数据快照。)。所以reids会重新创建一个新的rdb文件,就出现覆盖情况。

原因:

Rdb备份流程:

  • 当触发bgsave持久化时(满足配置条件或手动执行bgsave命令),主进程fork一个子进程进行持久化操作,主进程不参与任何持久化IO操作;
  • 为了不影响原有rdb文件的使用,子进程会将快照数据先写入到临时文件;
  • 当快照数据完全备份到临时文件时,就替换掉原有的rdb文件,从而得到最新数据的rdb文件;(rdb数据丢失的原因

故障原因总结:

出现故障的原因,是redis的数据回写机制上出现问题,redis回写机制分为:同步回写(SAVE)和异步回写(BGSAVE)。

  • 同步回写即SAVE命令,主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的。
  • 异步回写即BGSAVE命令,主进程fork后,复制自身并通过这个新的进程回写磁盘,回写结束后新进程自行关闭。由于这样做不需要主进程阻塞,系统不会假死,一般默认会采用这个方法。

我们再用的机制是异步回写(BGSAVE)。但是,此方法在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork会占用很大的内存资源。此时会导致fork进程分配不到内存。

之所以分配不到内存资源是和操作系统优化有关,即使操作系统有足够的内存资源,也会导致fork分配不到内存资源。通过查看我么现有服务器的Linux内核参数,发现阿里云提供的centos7.*操作系统内核参数vm.overcommit_memory使用的时默认值:“0”。

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

通过查询redis官网资料,建议上vm.overcommit_memory设置为“1”,这样能确保fork能分配到内存资源。不会出现异步同步(BGSAVE)机制失败的情况。

临时处理方法:(现在使用的处理方法)

在redis配置文件中,将stop-writes-on-bgsave-error yes修改为 stop-writes-on-bgsave-error no 。

官网资料处理方法:

修改内核参数 vi /etc/sysctl。设置 vm.overcommit_memory = 1 ,

然后执行:sysctl -p