磁盘只读故障排查实战:Linux 文件系统修复

磁盘只读(read-only filesystem)是线上最容易被误判为“服务挂了”的故障:进程还在、端口还通,但任何写操作都报 Read-only file system。日志写不进、上传失败、数据库卡死,表现千奇百怪。本文从如何确认只读、到用 dmesg 与 fsck 定位根因,再到安全修复与长效防护,给出一套可直接照做的排查流程,帮你把“假死”快速救活。

一、先确认是不是真的只读

不要急着重启。第一步是把“应用层报错”和“文件系统真的只读”区分开。最可靠的办法是看挂载选项,再实际写一个文件验证。

# 查看根分区挂载选项,留意有没有 ro
mount | grep ' on / '

# 实际写测试
touch /tmp/ro_test 2>/tmp/ro_err && echo "可写" || (echo "只读"; cat /tmp/ro_err)

如果 mount 输出里根或某分区带 ro 选项,或者 touch 明确报 Read-only file system,就确认是文件系统只读。下面这张表帮你把现象和结论对上号。

现象说明
mount 含 ro 选项文件系统被以只读方式挂载或自动降级
touch 报 Read-only file system确认该挂载点不可写
应用写日志失败但读正常典型只读表现,进程未崩溃
df 显示容量正常与“磁盘满”不同,要先排除空间问题

二、看内核日志:为什么变成只读

Linux 文件系统(EXT4/XFS 等)在检测到底层 I/O 错误时,会主动进入只读保护模式,目的是“宁可停写也不继续损坏数据”。所以只读几乎总是“果”,真正的“因”在日志里。配合 Web 服务器日志分析实战 的思路,先抓内核环形缓冲:

# 带时间戳查看内核日志,过滤关键错误
dmesg -T | grep -iE 'read-only|error|EXT4|XFS|I/O error|sda|nvme'

# 或查系统日志
journalctl -k -p err -b | tail -50

常见根因:云盘瞬时抖动、磁盘坏块、RAID 降级、虚拟机热迁移、内存故障触发内核 BUG。看到 EXT4-fs error 或 I/O error 基本就能锁定是底层存储问题,而不是应用 bug。

三、临时恢复:重新挂载为读写

如果业务需要立刻恢复,可尝试在线重新挂载为读写:

# 谨慎:仅用于紧急恢复
mount -o remount,rw /

# 指定分区
mount -o remount,rw /data

注意:若底层确实有未修复的错误,强制 rw 可能扩大数据损坏范围。这一步只能当作“先恢复服务”,之后必须做 fsck 彻底修复。如果 remount 仍然失败,说明错误严重,需要进入单用户或救援模式处理。

四、根因分类与对症处理

1. 文件系统错误:用 fsck 修复

文件系统元数据损坏是最常见原因。修复前必须先卸载(或在救援模式),绝对不能对挂载中的分区跑 fsck。

# EXT4:卸载后检查并自动修复
umount /dev/sda1
fsck -y /dev/sda1

# XFS:用 xfs_repair(不能在线,且先尝试 xfs_repair -n 预览)
xfs_repair -n /dev/sda1
xfs_repair /dev/sda1

2. 底层存储 / 云盘故障

云服务器优先去控制台看云盘状态、IOPS/吞吐是否异常,必要时换盘或工单。物理机用 SMART 看磁盘健康:

smartctl -a /dev/sda | grep -iE 'Reallocated|Pending|Uncorrectable|Overall'

3. 内核 / 内存触发的保护性只读

若 dmesg 出现 hung task、BUG 或大量内存纠错,可能是内核或硬件问题。升级内核、排查内存条、必要时迁移实例。

4. 容器场景里的“只读”

容器自身可能是只读层导致,不一定是宿主机故障。例如 Docker Compose 一键编排 里给容器加了 --read-only,或 overlay 所在宿主机磁盘只读会传导到容器。K8s 里 securityContext.readOnlyRootFilesystem: true 也会让写入失败——这类要在编排层面处理,而不是去修宿主机。

五、fsck 实战步骤

不同文件系统的检查命令不同,下面一张表对照清楚:

文件系统检查/修复命令能否在线
EXT2/3/4fsck -y /dev/sdXN否(需卸载)
XFSxfs_repair /dev/sdXN否(先 xfs_repair -n 预览)
Btrfsbtrfs check /dev/sdXN否(建议离线)
# 标准流程
# 1) 备份重要数据 / 打快照
# 2) 卸载目标分区(根分区需进救援模式)
umount /dev/sda1
# 3) 自动修复(交互确认选 y)
fsck -y /dev/sda1
# 4) 重新挂载验证
mount /dev/sda1 /data && touch /data/ro_test && echo "恢复可写"

小提示:LVM 或云盘环境下设备名可能是 /dev/vdb1、/dev/nvme0n1p1,用 lsblk 和 blkid 确认,别修错盘。类似“假死”现象也可以参考 文件描述符耗尽排查,两者表现相似但根因完全不同。

六、容器与云原生里的只读根

把容器根文件系统设为只读,是现代“不可变基础设施”的推荐做法,能减少攻击面、避免容器把日志/临时文件写爆宿主机。正确姿势是把需要写的地方用卷挂出来:

# Docker:根只读,临时目录与日志挂 volume
docker run --read-only -v app-tmp:/tmp -v app-log:/var/log myapp

# Kubernetes:只读根 + emptyDir 给可写目录
securityContext:
  readOnlyRootFilesystem: true
volumes:
  - name: tmp
    emptyDir: {}

七、如何避免再次只读

修复只是止血,长效防护才是关键:

  • 监控先行:对 dmesg 的 I/O error、磁盘 SMART、云盘健康做告警,别等业务报障才发现。
  • 配置稳健:/etc/fstab 用 UUID 挂载,了解 errors=remount-ro 的默认行为。
  • 架构隔离:日志、数据、临时文件分盘,避免根分区被写满或抖动传导。
  • 定期备份:云盘快照 + 应用级备份,修复失败时也能回滚。

性能与稳定性基线可参考 Linux 性能排查实战 与 Linux 内核参数调优,把磁盘、内存、网络监控一起做扎实。

八、落地 Checklist

步骤动作命令/要点
1 确认看挂载选项 + 写测试mount | grep ro;touch 测试
2 取证抓内核日志dmesg -T | grep -iE ‘error|EXT4|XFS’
3 判断区分文件错误/存储/容器看错误类型与场景
4 应急谨慎 remount rwmount -o remount,rw /
5 修复离线 fsckumount 后 fsck -y
6 防护监控+备份+隔离告警、快照、分盘

九、根分区只读、进不了系统怎么办

当根分区(/)本身只读且无法 remount,机器往往已经卡死或起不来。这种情况不能在线 fsck,必须离线修复:云服务器用厂商的“救援模式”把系统盘作为数据盘挂到另一台实例,再用 fsck 修复;物理机或本地虚拟机则从 Live CD / ISO 启动进入救援环境。核心原则不变——fsck 永远只修未挂载的分区。修完把系统盘挂回原实例重启即可。这类操作建议沉淀进应急预案,关键时刻能省下大量救火时间。

# 救援模式下:把系统盘挂载为数据盘后修复
mkdir -p /mnt/rescue
mount /dev/sdb1 /mnt/rescue
fsck -y /dev/sdb1
umount /mnt/rescue

磁盘只读并不可怕,可怕的是盲目重启或强制写导致二次损坏。记住这条主线:先确认、再取证、后修复、重防护,绝大多数只读故障都能在不丢数据的前提下恢复。

上一篇 nushell 实战:用结构化管道重塑命令行工作流
下一篇 Java 日期时间 API 实战:从 Date 到 java.time
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]