今天运行Redis时发生错误,错误信息如下:
(error) 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被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用。请查看Redis日志的详细错误信息。
方法一:
运行
config set stop-writes-on-bgsave-error no
命令后,关闭配置项stop-writes-on-bgsave-error解决该问题。使用这个命令后,访问报错停止,但是即使没有报错,数据存储也是不成功的。
后来查其他资料发现这样做其实是不好的,这仅仅是让程序忽略了这个异常,使得程序能够继续往下运行,但实际上数据还是会存储到硬盘失败!
方法二:
由于Redis是daemon模式运行的,没法看到详细的日志。所以修改配置文件设置logfile参数为文件(默认是stdout,建议以后安装完毕就修改这个参数为文件,不然会丢掉很多重要信息),重启Redis,查看日志,可以看到类似的错误:
Can’t save in background: fork: Cannot allocate memory
系统不能在后台保存,fork进程失败。
错误原因:
Redis的数据回写机制分同步和异步两种,
- 同步回写即SAVE命令,主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的。
- 异步回写即BGSAVE命令,主进程fork后,复制自身并通过这个新的进程回写磁盘,回写结束后新进程自行关闭。由于这样做不需要主进程阻塞,系统不会假死,一般默认会采用这个方法。
redis为了避免主进程假死,需要Fork一份主进程,然后在Fork进程内完成数据保存到硬盘的操作,如果Fork子进程的时候需要额外的内存不够了,那么Fork失败,进而数据保存硬盘也失败了。
解决方案:
修改内核参数vm.overcommit_memory = 1
内核参数overcommit_memory
1. 如果 vm.overcommit_memory = 1,直接放行
2. vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
3. vm.overcommit_memory = 2:则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行