解决 MISCONF Redis is configured to save RDB snapshots 异常详解

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 解决 MISCONF Redis is configured to save RDB snapshots 异常详解

java抛出异常内容

Caused by: io.lettuce.core.RedisCommandExecutionException: 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.
  at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135)
  at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108)
  at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120)
  at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111)
  at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:646)
  at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:604)
  at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:556)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
  at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
  at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
  at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
  at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
  at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
  at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
  at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
  at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
  at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
  ... 1 common frames omitted

image.gif

前言

最近遇到应用程序客户端在往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的日志还是系统的日志),一直怀疑是不是自己整错什么东西了。

发现原因:

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

有时候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.

image.gif

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

Redis后台保存模式依赖于现代操作系统中fork的copy-on-write语义:Redis forks(创建一个子进程)是父进程的完全副本。子进程将数据库转储到磁盘上,最后退出。

Redis在保存数据到硬盘时为了避免主进程假死,需要Fork一份主进程,然后在Fork进程内完成数据保存到硬盘的操作,如果主进程使用了4GB的内存,Fork子进程的时候需要额外的4GB,此时内存就不够了,因此,当redis使用的内存超过操作系统一半的内存的时候,For就失败了,进而数据保存硬盘也失败了。

快速解决办法:

修改redis.conf文件:vi打开redis-server配置的redis.conf文件,然后使用快捷匹配模式:/stop-writes-on-bgsave-error定位到stop-writes-on-bgsave-error字符串所在位置,接着把后面的yes设置为no即可。

stop-writes-on-bgsave-error no

image.gif

这就暂时解决了这个问题。但是,这个选项的作用是阻止redis通知写操作已经停止,并且在不将数据写入快照的情况下继续操作。这只是忽略了这个异常,使得程序能够继续往下运行,但实际上数据还是会存储到硬盘失败!

linux系统可以通过修改内存分配策略解决

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

# sysctl vm.overcommit_memory=1

建议解决办法

优化redis写入的代码,避免高频写入,减少非必要持久化的数据。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
19天前
|
存储 NoSQL Redis
Redis 持久化揭秘:选择 RDB、AOF 还是混合持久化?
Redis 是一个内存数据库,意味着它主要将数据存储在内存中,从而能够提供极高的性能。然而,作为内存数据库,Redis 默认情况下的数据不会永久保存。为了确保数据在重启或故障后能够恢复,Redis 提供了几种 **持久化机制**。这些机制允许 Redis 将内存中的数据保存到硬盘上,从而实现数据持久化。
94 22
Redis 持久化揭秘:选择 RDB、AOF 还是混合持久化?
|
2月前
|
存储 监控 NoSQL
【赵渝强老师】Redis的RDB数据持久化
Redis 是内存数据库,提供数据持久化功能以防止服务器进程退出导致数据丢失。Redis 支持 RDB 和 AOF 两种持久化方式,其中 RDB 是默认的持久化方式。RDB 通过在指定时间间隔内将内存中的数据快照写入磁盘,确保数据的安全性和恢复能力。RDB 持久化机制包括创建子进程、将数据写入临时文件并替换旧文件等步骤。优点包括适合大规模数据恢复和低数据完整性要求的场景,但也有数据完整性和一致性较低及备份时占用内存的缺点。
|
3月前
|
存储 缓存 NoSQL
大数据-45 Redis 持久化概念 RDB AOF机制 持久化原因和对比
大数据-45 Redis 持久化概念 RDB AOF机制 持久化原因和对比
60 2
大数据-45 Redis 持久化概念 RDB AOF机制 持久化原因和对比
|
3月前
|
存储 缓存 NoSQL
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
81 1
|
4月前
|
存储 NoSQL Redis
Redis的RDB快照:保障数据持久性的关键机制
Redis的RDB快照:保障数据持久性的关键机制
96 0
|
NoSQL Redis 网络协议
|
NoSQL Redis 网络协议
redis 异常解决办法
redis 异常解决办法 26069:M 08 Aug 17:06:58.858 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1161 0
|
18天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
162 85
|
3月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
87 6
|
15天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。