专注,勤学,慎思。戒骄戒躁,谦虚谨慎

just do it

导航

Debugging: MISCONF Redis is configured to save RDB snapshots(译)

最近遇到应用程序客户端在往redis中写入数据的时候发生了一个这样一个错误:
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. 
第一次遇到这种错误还是蛮好奇的,主要是它无法重现(或必现),只是会偶尔出现,客户端抛出该异常后redis服务状态也是正常的,特意查了一下相关的资料,结合当时自己的操作场景,还算是解释的通的。
该问题的大概原因在于:开启了snapshot的持久化模式,且在大量写入的时候bgsave持久化异常,导致客户端写入数据失败,原因译文中有提及。
当然解决办法也很简单,设置参数stop-writes-on-bgsave-error为no,也即bgsave异常的时候不要阻止继续写入数据。

笔者的环境是:centos 7+ Redis 5.0.1;
操作场景是:并发线程以pipline的方式往redis中写入数据,这样会频繁促使发生后台持久化线程pgsave的工作(操作系统远大于redis中的数据占用内存);
异常现象:客户端会偶发上述错误,但是redis服务本身没有异常,事后可以正常访问。
经检查redis的日志和系统日志,均没有记录到异常信息,应该是redis设置了stop-writes-on-bgsave-error=yes的情况下,服务端bgsave失败之后一种正常的阻止继续写入行为。
同时,尽管在操作系统的内存充足的情况下,redis的bgsave为什么会失败,这也是一个需要思考的问题。
这个问题一直没有查到日志(不管是redis的日志还是系统的日志),一直怀疑是不是自己整错什么东西了,直至发现这个哥们也提到这个问题:the issue happens intermittently and dont know why. no indication in the logs.

另:redis的bgsave是一个独立于redis服务的进程,对于在大批量写入的情况下,经常可以看到一个redis实例下的这个bgsave独立进程(进程之间是无法共享内存的)

 

 

以下为译文,原文地址:https://blog.sakuragawa.moe/debugging-misconf-redis-is-configured-to-save-rdb-snapshots/

 

有时候Redis会抛出如下的错误:

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.

发生此错误是因为BGSAVE失败。很多时候BGSAVE失败是因为fork无法分配内存。很多时候fork无法分配内存(尽管机器有足够的可用RAM),因为操作系统的优化冲突。

Override Error in Redis Configuration

使用redis cli,您可以停止尝试保存快照:

config set stop-writes-on-bgsave-error no

这是一个快速的解决方法,但是如果您关心使用它的数据,您应该首先检查一下BGSAVE失败的原因。
这就暂时解决了这个问题。但是,过度查看这个错误是一种可怕的方法,因为这个选项的作用是阻止redis通知写操作已经停止,并且在不将数据写入快照的情况下继续操作。这只是忽略了这个错误。

Save Redis on Low Memory

由于内存不足,bgsave过程中可能出现错误。
发生此错误是因为BGSAVE失败。在BGSAVE期间,Redis fork一个子进程以将数据保存到磁盘上。
虽然BGSAVE失败的确切原因可以从日志中查看(通常在/var/log/redis/redis-服务器日志但是很多时候BGSAVE失败是因为fork不能分配内存。很多时候fork无法分配内存(尽管机器有足够的可用RAM),因为操作系统的优化冲突。
Redis常见问题中可以看出:
Background saving is failing with a fork() error under Linux even if I've a lot of free RAM!

Redis后台保存模式依赖于现代操作系统中fork的copy-on-write语义:Redis forks(创建一个子进程)是父进程的完全副本。子进程将数据库转储到磁盘上,最后退出。
理论上,子进程应该使用与父进程作为副本一样多的内存,但实际上由于大多数现代操作系统实现的“写时拷贝”语义,父进程和子进程将共享公共内存页。
只有在子级或父级中更改页时,才会复制该页。因为理论上,当子进程保存时,所有的页面都可能会发生变化,所以Linux无法预先知道子进程将占用多少内存,因此,如果overcommit_memory设置设置为zero fork,则将失败,除非有足够多的可用RAM来真正复制所有父内存页,结果是,如果你有一个3gb的Redis数据集,而只有2gb的空闲内存,那么它将失败。

# echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
# sysctl vm.overcommit_memory=1

Redis不需要操作系统认为的那样多的内存来写入磁盘,因此可能会先发制人地让fork失败。

 

posted on 2020-11-10 23:20  MSSQL123  阅读(149)  评论(0编辑  收藏  举报