单实例Redis Docker部署运行数小时报只读副本无法写入错误
问题根因说明
单实例Redis触发READONLY You can't write against a read only replica报错和主从副本逻辑无关,是持久化异常触发内置写保护机制的典型表现,错误信息里的replica字样属于通用报错文案,在单实例场景下存在误导性。
结合你提供的Docker部署、Redis 7.0.0版本、目录权限配置,故障触发的常见原因按概率从高到低排序:
- Redis 7.0.0为7.0系列初始大版本,存在已知AOF重写bug:当AOF后台重写进程异常退出(比如被OOM杀掉、IPC通信中断),主进程不会正确重置持久化状态,会错误将自身标记为只读状态,该bug在7.0.1及后续补丁版本中修复。
- Redis默认配置
stop-writes-on-bgsave-error yes,只要RDB快照生成、AOF重写/fsync任何一个后台持久化动作失败,Redis会全局禁止所有写入操作,返回和副本只读完全一致的错误。你当前的部署存在两个容易触发持久化失败的隐患:- 仅单独挂载
appendonlydir目录,没有挂载Redis的整个工作目录。Redis AOF重写时会先在工作目录根路径生成临时文件,重写完成后才会移动到appendonlydir目录内,如果工作目录位于容器可写层,容器内部存储空间耗尽、或者没有对应写入权限,会直接导致重写失败。 - 你修改了容器内redis用户的uid/gid为1001,如果宿主机systemd默认开启
RemoveIPC=yes配置,当宿主机上uid为1001的用户退出登录会话时,系统会自动清理该用户创建的所有共享内存、信号量等IPC资源,导致Redis主进程和后台持久化子进程通信中断,触发持久化失败。该问题无固定触发时间,通常在服务运行数小时、对应用户会话超时退出后出现,和你描述的故障特征完全匹配。
- 仅单独挂载
- 持久化目录所在磁盘空间耗尽、inode耗尽,也会导致写入失败触发写保护。
排查步骤
- 进入Redis容器执行
redis-cli INFO persistence,重点查看aof_last_bgrewrite_status、rdb_last_bgsave_status字段值,如果为err,对应错误原因会记录在aof_last_cause、rdb_last_cause字段中,可直接定位持久化失败的具体诱因。 - 查看宿主机
dmesg或/var/log/messages日志,检查故障时间点是否存在Redis进程被OOM Killer杀掉、IPC资源被清理的记录。 - 在宿主机持久化目录所在分区执行
df -h检查剩余磁盘空间,执行df -i检查剩余inode数量,排除存储资源耗尽问题。 - 进入容器执行
redis-cli CONFIG GET dir,确认Redis工作目录为你预期的持久化挂载路径,而非容器内部默认路径。
修复方案
- 版本升级:将基础镜像从
redis:7.0.0升级到7.0.15及以上的7.0系列稳定补丁版本,避开初始版本的AOF重写状态标记bug。 - 挂载配置修正:不要单独挂载
appendonlydir子目录,直接将宿主机持久化目录挂载到Redis的默认工作目录/data,保证Redis对整个工作目录有完整读写、创建临时文件、移动文件的权限。 - 系统配置修正:修改宿主机
/etc/systemd/logind.conf配置,将RemoveIPC参数设置为no,执行systemctl restart systemd-logind生效,避免非root用户的IPC资源被系统自动回收。 - 兜底配置(非根因修复,仅做业务容灾):在redis.conf中添加配置
stop-writes-on-bgsave-error no,即使持久化失败也不会触发全局写禁止,避免业务中断。注意该配置仅为兜底手段,必须同步排查解决持久化失败的根因,否则会出现持久化中断、数据丢失的风险。 - 配置校验:重启容器后手动执行
redis-cli BGREWRITEAOF触发一次AOF重写,等待1分钟后再次查询INFO persistence,确认aof_last_bgrewrite_status为ok即可。
内容的提问来源于stack exchange,提问作者Glen
相关产品推荐
相关产品推荐

