
我不会起名字322· 后端 / 算法 / 数据库 技术栈 力扣 Hot100 Go 项目 Redis MySQL文章目录Redis 突然只能读不能写MISCONF 报错的 3 类触发条件与 4 步恢复一、这条报错到底在说什么二、3 类触发条件条件 1磁盘写不进去最常见条件 2fork 失败容器里高频条件 3你连的是只读从节点报错不同但现象一样三、命令清单四、4 步恢复第 2 步最容易被做错五、配置模板防再犯六、总结Redis 突然只能读不能写MISCONF 报错的 3 类触发条件与 4 步恢复线上 Redis 一点征兆没有突然所有写入都失败了客户端抛的是这一句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. Please check Redis logs for details about the error.读取完全正常只有写入被拒。更让人困惑的是Redis 明明是内存数据库为什么写不进去要怪「磁盘」答案在最后一句配置里Redis 为了保护持久化的一致性在 RDB 快照失败时会主动关闭写命令。这不是 Redis 坏了是一道保护机制起作用了——它宁可让你写不进去也不愿意让你以为数据已经落盘、实际上没有。这篇文章讲清这道保护机制的 3 类触发条件以及真正正确的 4 步恢复动作其中第 2 步在网上被大量错误地当成「解决方案」。一、这条报错到底在说什么触发逻辑只有一条Redis 配置了 RDB 快照save 指令 ↓ stop-writes-on-bgsave-error yes默认值生产建议保持 yes ↓ 最近一次 BGSAVE 失败了 ↓ 所有可能修改数据集的命令被拒绝SET/DEL/INCR/LPUSH… GET 之类的读命令不受影响所以排查的第一步不是改配置而是去问上一次 BGSAVE 为什么失败# 看持久化状态重点看这两个字段redis-cli INFO persistence# rdb_last_bgsave_status:err ← 上一次快照失败# rdb_last_save_time:1696300000 ← 最后一次成功的时间戳二、3 类触发条件条件 1磁盘写不进去最常见BGSAVE 要把内存里的数据写成 RDB 文件写不进去的常见原因磁盘满了df -h一看就知道但往往是别的进程把盘占满了目录没有写权限Redis 进程用户 ≠dir的所有者或者用了只读挂载dir配置指向了一个不存在的路径改过配置文件但没建目录磁盘配额quota或 inode 用尽df -i。日志里通常长这样# Write error saving DB on disk: No space left on device # Error trying to save the DB, cant exit.条件 2fork 失败容器里高频BGSAVE 靠fork()子进程来做快照。fork 失败时日志是# Cant save in background: fork: Cannot allocate memory两个高频成因vm.overcommit_memory 0内核保守估计觉得 fork 一个和父进程一样大的进程可能超内存直接拒绝。Redis 官方明确要求设成 1sysctlvm.overcommit_memory1echovm.overcommit_memory 1/etc/sysctl.conf容器/cgroup 限制Redis 在容器里fork 瞬间的内存需求超过 cgroup limit哪怕实际用的是 Copy-On-Write内核在限定时仍可能按最坏情况判断。这种场景要么放宽容器内存要么把 Redis 放到内存更充裕的节点上。顺带一个相关现象INFO stats里的latest_fork_usec很大比如超过 1 秒说明 fork 很慢——fork 期间主进程是阻塞的这也是 Redis 延迟尖刺的常见来源。条件 3你连的是只读从节点报错不同但现象一样有一类「只能读不能写」不是 MISCONF报错是READONLY You cant write against a read only replica.但它经常和上面那类混淆因为现象完全一致读正常、写失败。区分方法很简单redis-cli INFO replication# role:slave ← 说明你连的是从节点常见成因客户端连错了地址主从切换后VIP 指向了从节点、或者用了读写分离的客户端却把写请求发到了读连接上。这一类改stop-writes-on-bgsave-error完全没有用必须换连接。三、命令清单命令作用看什么redis-cli INFO persistence持久化状态⭐rdb_last_bgsave_status是不是errredis-cli INFO stats | grep latest_fork_usecfork 耗时超过 1s 说明 fork 慢会有延迟尖刺redis-cli CONFIG GET dir/dbfilename落盘路径路径是否存在、是否可写df -h dir/df -i dir磁盘空间 / inode是否满了ls -ld dir目录权限Redis 进程用户有没有写权限tail -n 200 logfile服务端日志⭐真正的原因只在这里redis-cli CONFIG GET save快照策略是不是配了save 关掉 RDBredis-cli CONFIG GET stop-writes-on-bgsave-error保护开关默认yesredis-cli BGSAVE手动触发一次用来验证修复是否成功redis-cli LASTSAVE最后成功时间与当前时间对比看多久没成功过了redis-cli INFO replication主从角色排除「连到了从节点」sysctl vm.overcommit_memory内核参数应该是 1redis-cli CONFIG GET rename-command命令重命名有没有把SAVE/BGSAVE改掉某些加固规范会这么做四、4 步恢复第 2 步最容易被做错第 1 步看日志拿到真实原因。tail-n200/var/log/redis/redis-server.log|grep-iEerror|fail|fork|save这一步不能跳。磁盘满、权限不足、fork 失败三者的修复动作完全不同。凭猜改配置只会把问题盖住。第 2 步恢复写入这是临时动作不是修复。redis-cli CONFIG SET stop-writes-on-bgsave-error no网上大量教程到此结束但这句话的真实含义是「Redis 你别再拦我了数据能不能落盘我不在乎了」。它是拆掉烟雾报警器不是灭火。执行之后写入立刻恢复 ✅但你的数据处于没有成功持久化的状态❌ —— 此刻宕机从最后一次成功的 RDB 之后的所有写入都会丢所以第 2 步和第 3 步必须连着做中间不能隔夜。第 3 步按第 1 步找到的原因修根因。根因修复动作磁盘满清理空间优先清dir之外的东西日志、core dump、旧备份并加磁盘告警目录不可写chown redis:redis dir确认不是只读挂载dir不存在建目录并CONFIG SET dir pathCONFIG REWRITEfork 失败sysctl vm.overcommit_memory1容器场景放宽内存限制连的是从节点改客户端连接地址READONLY与 MISCONF 是两回事BGSAVE被 rename 禁用改回rename-command配置或改用手动备份方式第 4 步验证并把保护开关开回去。redis-cli BGSAVE# 手动跑一次redis-cli INFO persistence|greprdb_last_bgsave_status# 应该是 okredis-cli LASTSAVE# 时间戳应该刚刚更新# ⭐ 验证通过后把保护重新打开redis-cli CONFIG SET stop-writes-on-bgsave-erroryesredis-cli CONFIG REWRITE只有rdb_last_bgsave_status:ok之后再把保护开回yes才是真正恢复了。五、配置模板防再犯# 落盘路径指向一个确定存在、确定可写、空间充足的目录 dir /data/redis dbfilename dump.rdb # 快照策略按业务可容忍的丢失窗口来配 save 900 1 # 15 分钟内至少 1 个 key 变化 save 300 10 # 5 分钟内至少 10 个 key 变化 save 60 10000 # 1 分钟内至少 10000 个 key 变化 # 缓存型 Redis 可以干脆关掉 RDBsave 但要清楚这意味着重启即丢 # 保护开关生产保持 yes stop-writes-on-bgsave-error yes # AOF对数据安全性要求高时开启 appendonly yes appendfsync everysec # 日志出事时唯一的证据来源 logfile /var/log/redis/redis-server.log loglevel notice配套的两条运维纪律磁盘使用率告警阈值设到 80%不要等 95% 才告警——Redis 快照需要连续空间等到快满时往往已经来不及监控rdb_last_bgsave_status不是只看写入是否可用。它变成err就是明确的告警信号比接口报错早得多。六、总结MISCONF 不是故障是保护机制生效了stop-writes-on-bgsave-error yes在 BGSAVE 失败时主动拒写防止你以为数据已落盘。读命令不受影响所以现象是「能读不能写」。3 类触发条件① 磁盘/权限/路径导致写不进去最常见② fork 失败vm.overcommit_memory0或容器内存限制③ 你连的是只读从节点报错是READONLY与 MISCONF 无关改保护开关没用。CONFIG SET stop-writes-on-bgsave-error no只是临时恢复手段等于拆掉烟雾报警器。真正的修复是去服务端日志里找出 BGSAVE 失败的原因并处理掉。恢复流程闭环看日志定位 → 临时放开写入 → 修根因 → 手动BGSAVE验证rdb_last_bgsave_status:ok→把保护开回yes并CONFIG REWRITE。防再犯靠两件事磁盘告警阈值设 80%以及把rdb_last_bgsave_status纳入监控——它变err时接口还没开始报错那才是最佳处理窗口。本文基于 Redis 6/7 的行为stop-writes-on-bgsave-error的默认值、字段名在各版本一致但INFO persistence的细分字段在不同版本略有差异以你实际版本的输出为准。