一次 Redis MISCONF 故障,背后竟是磁盘 I/O 异常

举报
Lucifer三思而后行 发表于 2026/10/14 13:11:23 2026/10/14
【摘要】 前言昨天碰到一个 Redis 故障,应用突然报错,提示 Redis 无法写入。一开始看到 MISCONF,以为就是常见的 RDB 持久化失败。之前也遇到过类似问题,大部分都是磁盘空间不足,清理一下空间或者处理持久化目录就能恢复。结果排查下来发现,这次还不太一样:Redis 所在服务器的磁盘空间还剩 400 多 GB,内存也没什么压力,Redis 进程一直在,但就是无法写入。继续查下去才发现...

前言

昨天碰到一个 Redis 故障,应用突然报错,提示 Redis 无法写入。

一开始看到 MISCONF,以为就是常见的 RDB 持久化失败。之前也遇到过类似问题,大部分都是磁盘空间不足,清理一下空间或者处理持久化目录就能恢复。

结果排查下来发现,这次还不太一样:Redis 所在服务器的磁盘空间还剩 400 多 GB,内存也没什么压力,Redis 进程一直在,但就是无法写入。

继续查下去才发现 Redis 的 RDB 文件和日志都停留在了 9 月 30 日,记得当时是工厂断电导致虚拟化重启了,这台主机恰好是运行在虚拟化上,应该是那时候导致的问题,而今天已经是 10 月 13 日,看来这台 Redis 服务器可能也没那么重要。

顺着这个时间点往下查,最后才发现,真正出问题的不是 Redis,而是 Linux 的根文件系统。

本文记录一下这次排查过程。

一、应用突然报 Redis MISCONF

最开始是应用服务器报错,Java 日志中出现大量 Redisson 异常,核心报错如下:

org.redisson.client.RedisException:
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.

Redis 地址是 10.235.39.27:6379,这个报错其实比较明确。

Redis 配置了 RDB 持久化,但是当前无法将快照保存到磁盘。由于开启了 stop-writes-on-bgsave-error 保护机制,Redis 会拒绝可能修改数据的命令。

一般遇到这种情况,我会先看以下几个地方:

  1. 磁盘是不是满了
  2. Redis 数据目录有没有权限
  3. 内存是否充足
  4. RDB 保存到底报了什么错

先登录服务器看看。

二、磁盘空间正常,Redis 进程也在

登录 Redis 服务器,先检查系统资源:

df -h
df -i
free -h
ps -ef | grep '[r]edis-server'

磁盘情况:

Filesystem                         Size  Used Avail Use%
/dev/mapper/ubuntu--vg-ubuntu--lv  490G  7.2G  463G   2%

490G 的根分区,只用了 7.2G,剩余 463G,inode 使用率只有 1%,也没什么问题。

再看内存:

              total    used    free    available
Mem:          7.8Gi    278Mi   6.9Gi   7.2Gi
Swap:         4.0Gi      0B    4.0Gi

系统内存也很充足。

Redis 进程正常:

redis 969 1 /usr/bin/redis-server *:6379

这就有点奇怪了。

磁盘没满,内存正常,Redis 进程也没有退出,为什么 RDB 会保存失败?

本来准备直接查 Redis 的持久化状态:

redis-cli -p 6379 INFO persistence

结果返回:

NOAUTH Authentication required.

Redis 开启了密码认证,现场暂时没有拿到密码。

既然 Redis 内部状态暂时查不了,那就先从操作系统和配置文件继续排查。

三、RDB 文件竟然停留在十几天前

先查看 Redis 的持久化配置:

grep -En \
'^[[:space:]]*(dir|dbfilename|save|appendonly|logfile)[[:space:]]' \
/etc/redis/redis.conf

save 900 1
save 300 10
save 60 10000

dbfilename dump.rdb
dir /var/lib/redis
appendonly no

配置比较常规,启用了 RDB,没有开启 AOF。

接着检查 RDB 文件:

ls -lh --full-time /var/lib/redis/

-rw-rw---- 1 redis redis 11M
2026-09-30 19:26:03 dump.rdb

看到这里就感觉不太对了。

当天是 10 月 13 日,RDB 文件最后更新时间却是 9 月 30 日,已经过去十几天了。

按当前配置,只要满足相应的数据变更条件,Redis 就会尝试生成 RDB 快照。正常情况下,业务持续使用 Redis,不应该这么长时间都没有新的快照。

当然,单凭文件时间还不能直接判断持久化失败,毕竟还要看期间有没有数据变更。

继续检查 Redis 日志:

tail -100 /var/log/redis/redis-server.log

发现日志也停留在了 9 月 30 日。

最后几条记录:

30 Sep 2026 19:26:03
Background saving terminated with success

30 Sep 2026 19:41:04
1 changes in 900 seconds. Saving...

19:26 的 RDB 保存还是成功的,19:41 又触发了一次保存,但后面没有看到对应的成功记录。

而且 Redis 日志也没有继续更新,两个文件都停留在同一天,这就值得注意了。

如果只是 Redis RDB 保存失败,正常情况下日志里应该能找到一些错误信息。但现在连日志都不更新了,是不是文件系统本身出了问题?

四、Redis 目录权限正常,却无法写入

先检查 Redis 数据目录权限:

ls -ld /var/lib/redis
ls -lh /var/lib/redis/

drwxr-x--- redis redis /var/lib/redis
-rw-rw---- redis redis dump.rdb

Redis 进程本身就是使用 redis 用户运行的,目录属主和权限看起来都没有问题。

再检查一下完整路径:

namei -l /var/lib/redis/dump.rdb

也没发现明显异常。

那就直接测试一下 redis 用户能不能写:

sudo -u redis test -w /var/lib/redis \
  && echo "DATA WRITABLE" \
  || echo "DATA NOT WRITABLE"

DATA NOT WRITABLE

再测试日志文件:

sudo -u redis test -w /var/log/redis/redis-server.log \
  && echo "LOG WRITABLE" \
  || echo "LOG NOT WRITABLE"

LOG NOT WRITABLE

这下有意思了。

Redis 用户明明拥有数据目录和日志文件的写入权限,但实际检查却显示无法写入。如果只是普通权限问题,通常能从属主、权限位或者 ACL 中找到原因。

但这里都没发现明显异常。

于是继续检查文件系统的挂载状态:

findmnt -T /var/lib/redis -o TARGET,SOURCE,FSTYPE,OPTIONS

TARGET SOURCE                            FSTYPE OPTIONS
/      /dev/mapper/ubuntu--vg-ubuntu--lv ext4   ro,relatime

看到 ro,问题一下就清楚了。

根文件系统已经变成只读了。

正常情况下应该是 rw,现在却是 ro,难怪 Redis 无法保存 RDB,日志也无法继续写入。

之前一直在检查 Redis 目录权限,实际上根本不是目录权限的问题,而是整个根文件系统都不允许写入了。不过问题还没结束,Linux 为什么会把根文件系统切换成只读?

五、查内核日志,终于找到根因

既然文件系统已经只读,那就得查一下内核日志:

journalctl -k --since "2026-09-30" \
  --no-pager | \
grep -Ei 'I/O error|EXT4-fs|read-only|remount'

这一查,问题就出来了。

日志中出现大量磁盘 I/O 错误:

blk_update_request: I/O error, dev sda

EXT4-fs warning (device dm-0):
I/O error writing to inode

Buffer I/O error on device dm-0

继续往下看:

EXT4-fs error (device dm-0):
Detected aborted journal

EXT4 的 Journal 已经异常中止。

更关键的是下面这条:

Sep 30 20:27:24
EXT4-fs (dm-0):
Remounting filesystem read-only

时间终于对上了,9 月 30 日 20:27:24,Linux 明确记录了将根文件系统重新挂载为只读的操作。

而在此之前,磁盘已经出现大量 I/O 超时:

sd 2:0:0:0: [sda]
timing out command, waited 1080s

1080 秒,整整 18 分钟。部分磁盘读写请求等待了这么长时间,最后还是失败了。

后面又陆续出现超级块写入失败:

EXT4-fs (dm-0):
I/O error while writing superblock

到这里,整个问题基本串起来了:

  1. 9 月 30 日,底层磁盘出现 I/O 异常,导致 EXT4 Journal 中止,Linux 将根文件系统切换为只读。
  2. Redis 的 RDB 文件和日志都放在根文件系统上,自然也就无法继续写入。
  3. 等到应用触发 Redis 写操作时,就出现了最开始看到的 MISCONF。

所以这次 Redis 报错,实际上只是底层存储故障在应用层的表现。

六、再看磁盘,发现根文件系统跨了两块盘

继续确认服务器环境:

systemd-detect-virt

vmware

这是一台 VMware 虚拟机。

再看磁盘结构:

lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS,RO,TYPE

sda                         100G
├─sda1                        1M
├─sda2                        2G ext4 /boot
└─sda3                       98G LVM2_member
  └─ubuntu--vg-ubuntu--lv   498G ext4 /

sdb                         400G LVM2_member
└─ubuntu--vg-ubuntu--lv     498G ext4 /

这里还有个需要注意的地方。

这台服务器的根文件系统使用了 LVM,而且跨了两块虚拟磁盘,一块 100G,一块 400G,最终组成了一个约 498G 的逻辑卷。

前面内核日志中的错误主要指向 /dev/sda,也就是说,即使另一块磁盘正常,只要其中一块出现 I/O 问题,就可能影响整个根文件系统。

当然,虚拟机内部看到 /dev/sda 报错,不代表一定是物理磁盘损坏。

还需要 VMware 管理员检查对应的 VMDK、Datastore、ESXi 存储路径等,才能进一步确认底层到底发生了什么。

七、虚拟机重启,Redis 恢复启动

找到问题后,原本准备继续检查 VMware 存储,再考虑文件系统修复。

不过在处理过程中,VMware 管理员已经直接重启了虚拟机,重启过程还卡了一会儿。

控制台一直显示:

A stop job is running for Advanced key-value store
(5min 17s / no limit)

这里的 Advanced key-value store 就是 Redis,说明 systemd 一直在等待 Redis 服务停止。

至于 Redis 为什么迟迟没有退出,当时没有进一步拿到进程状态,不能直接判断是 RDB 保存卡住,还是底层 I/O 导致的阻塞。

后来虚拟机总算完成了重启。

重新登录后,先检查系统启动时间:

uptime
who -b

system boot 2026-10-13 14:52

再看根文件系统:

findmnt /

TARGET SOURCE                            FSTYPE OPTIONS
/      /dev/mapper/ubuntu--vg-ubuntu--lv ext4   rw,relatime

这次已经恢复成 rw 了。

检查本次启动的内核日志,也没有发现新的磁盘 I/O 错误。

再看 Redis:

systemctl status redis-server --no-pager

Active: active (running)
Status: "Ready to accept connections"

Redis 在 14:53 正常启动,6379 端口也已经监听。

ss -lntp | grep 6379

LISTEN 0 511 0.0.0.0:6379

到这里,操作系统和 Redis 服务都已经重新起来了。

不过重启后检查发现,dump.rdb 仍然是 9 月 30 日的文件。因为这套 Redis 主要用于缓存,业务数据可以重新加载,所以这次没有强求恢复 9 月 30 日之后的缓存内容。

需要说明的是,现场最后还没有完成 Redis 认证后的 SET/GET 和 INFO persistence 验证,因此目前能确认的是系统恢复读写、Redis 服务正常启动,不能仅凭进程状态就认定 Redis 写入和 RDB 持久化全部恢复。

最后

这次 Redis 故障,表面上是 RDB 持久化失败,实际上是底层磁盘 I/O 异常导致 EXT4 文件系统变成了只读。

排查过程中有个细节值得注意:磁盘空间充足,不代表文件系统就能正常写入。

以后再遇到类似的 MISCONF,除了检查 Redis 持久化状态和磁盘空间,也可以顺手看一下文件系统:

findmnt /
dmesg -T | grep -Ei 'I/O error|EXT4-fs|read-only'

另外,这次重启后虽然系统恢复了读写,Redis 也正常启动,但 VMware 底层存储问题还需要进一步确认,不能因为服务起来了就认为故障彻底解决。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。