跳到主要内容

故障排查与最佳实践

排障总纲​

对象存储的故障看起来五花八门,其实可以用三个问题快速缩小范围:

  1. 影响面:一个桶、一个前缀,还是全集群?单桶出问题多半是权限或生命周期规则;全集群出问题多半是仲裁、网络或磁盘。
  2. 读写哪边:只能读不能写,通常是写仲裁不足或磁盘写满;读写都不行,通常是节点或池整体不可用。
  3. 所有客户端还是个别客户端:个别客户端报错,先怀疑它的密钥、时钟、SDK 版本;全都报错才看服务端。

先跑这三条命令,八成的问题当场就能定位:

# 集群与磁盘状态,第一眼就看它
mc admin info cluster

# 服务端日志,找 error / warning 关键字
sudo journalctl -u minio --since "30 min ago" | grep -iE 'error|warn|offline'

# 看具体请求为什么被拒(403/500 必备)
mc admin trace -v --status-code 403 cluster
别急着重启

MinIO 的很多告警是瞬时的(网络抖动、磁盘控制器超时),重启只会掩盖现场。先抓日志和 mc admin info 的输出,再决定动作。重启前把 mc admin info --json 存一份,事后对比能看出丢了多少盘。

磁盘故障​

怎么发现​

三个信号,按可靠程度排序:

  • 监控告警:minio_cluster_drive_offline_total 大于 0,这是最快的。
  • mc admin info:Drives 那一行变成 15 drives online, 1 drives offline,还会标出是哪台节点的哪块盘。
  • 服务端日志:disk offline、drive ... is not available、I/O error。

磁盘故障后的处理流程​

以「一块盘彻底坏了」为例,标准动作是:

# 1. 确认坏的是哪块盘(节点 + 挂载点)
mc admin info cluster

# 2. 在对应节点上看内核日志,确认是硬件问题
sudo dmesg -T | grep -iE 'error|reset|failed' | tail -20

# 3. 换盘后格式化并挂载(挂载点必须和原来完全一致)
sudo mkfs.xfs -f /dev/vdb
sudo mount /dev/vdb /mnt/disk1
sudo chown -R minio-user:minio-user /mnt/disk1

# 4. 重启该节点的服务,让它重新识别这块盘
sudo systemctl restart minio

# 5. 触发修复(先用 dry-run 看范围)
mc admin heal --dry-run --recursive cluster
mc admin heal --recursive cluster

影响范围有多大​

这是运维最关心的问题,答案取决于纠删码集合的布局:

  • 只影响该盘所在集合的对象,其他集合完全不受影响。16 盘一个集合时,每个对象都少了 1 个分片,但没有对象会因此丢失,业务侧通常无感。
  • 读写继续可用,前提是丢盘数没有超过校验值。EC:4 下坏 4 块盘还能读写,坏第 5 块就开始有对象读不出来。
  • 修复期间性能下降:heal 会读其他分片、重建、回写,磁盘 I/O 和网络流量都会明显上升。大容量盘的修复可能持续数小时到数天。
  • 修复期间冗余下降:只有 1 块盘坏、正在重建时,再坏 1 块还能扛;但如果已经坏了 3 块,第 4 块坏掉就只剩最后一点余量了。坏盘要尽快换,不要攒着。
别手工「搬数据」

有人看到某块盘空了,想用 cp 把别的盘上的文件拷过去「补上」——这是最危险的操作。MinIO 的分片带校验和元数据,手工拷贝会破坏一致性,导致整块盘被判定为损坏。换盘后让 MinIO 自己 heal,不要碰盘上的文件。

节点掉线​

排查顺序​

节点掉线时按这个顺序查,从便宜到贵:

# 1. 网络通不通(ICMP 可能被禁,直接测端口更准)
ping -c 3 minio3.example.net
nc -zv minio3.example.net 9000

# 2. 服务在不在
ssh minio3.example.net 'systemctl status minio --no-pager'

# 3. 时间同步是否正常(集群对时钟很敏感)
ssh minio3.example.net 'chronyc tracking'

# 4. 数据盘挂载是否还在
ssh minio3.example.net 'df -h /mnt/disk*'

# 5. 证书是否过期(TLS 集群常见)
openssl s_client -connect minio3.example.net:9000 -servername minio3.example.net 2>/dev/null | openssl x509 -noout -dates

常见根因按出现频率排:磁盘挂载丢失(重启后 fstab 没生效)、证书过期、时间偏差过大、服务 OOM 被杀、网络分区。

掉一个节点还能不能扛​

以 4 节点 × 4 盘、EC:4 为例:

故障每集合丢盘读写说明
掉 1 块盘1正常正常还有 3 块余量
掉 4 块盘(不同节点)4正常正常余量耗尽,再来一块就危险
掉 1 个节点(4 块盘)4正常正常正好卡在边界上
掉 2 个节点(8 块盘)8部分失败拒绝超过校验值,数据丢失

「掉一个节点正好卡在边界」这件事要特别记住:EC:4 的 4 节点集群,同时挂两个节点就是数据丢失。所以节点故障要当 P0 处理,不能因为「还能读写」就慢慢修。

集群不可写​

写请求全部失败是最紧急的故障。按下面这张表逐项排除:

现象可能原因确认方式处置
503 Service Unavailable写仲裁不足,丢盘数达到校验值mc admin info 看 offline 盘数优先恢复节点/磁盘
400 / 签名错误客户端与服务端时间偏差超过 15 分钟date 对比、chronyc tracking修 NTP
Access Denied密钥错误或策略变更mc admin trace --status-code 403核对策略
写入后立刻失败,日志报磁盘满磁盘使用率接近 99%df -h、监控水位清理或扩容
所有请求超时某节点网络分区、负载均衡打到坏节点mc admin info、LB 健康检查摘除坏节点
TLS 握手失败证书过期或 CA 未分发openssl s_client换证书并全节点重启
多池部署的特殊风险

如果集群有多个服务器池,任意一个池完全不可用,整个部署的 I/O 都会停止——MinIO 无法判断请求原本该路由到哪个池,继续服务可能造成不一致。这不是 bug,是设计上的安全选择。所以多池部署要保证每个池的可用性都在监控范围内,别只盯着总容量。

脑裂与分区​

「脑裂」在 MinIO 里的表现和传统分布式系统不太一样,理解仲裁规则就不会慌:

  • 校验值小于集合盘数的一半(比如 16 盘 EC:4):读写仲裁都是 12。网络分区导致一半盘不可见时,剩下 8 块达不到 12,读写都停,反而不会脑裂。
  • 校验值正好等于集合盘数的一半(比如 16 盘 EC:8):写仲裁被提高到 K + 1 = 9。这样即使集群被分成两半(各 8 块盘),两边都写不了,避免同一对象被写到两个「半边」上产生两个不一致的版本。读仲裁仍是 8,所以读可能还能成功。

处置原则只有一条:恢复网络,不要试图手工修复数据。

  • 分区恢复后,MinIO 会自动重新达成仲裁并继续服务。
  • 如果期间有节点被强制重启过,检查 mc admin info 和日志里是否有 heal 相关告警,必要时手动 mc admin heal。
  • 绝对不要为了「让集群先跑起来」去删盘上的文件、改 xl.meta、或者用 mc rm 清理「看起来坏了」的对象——这些动作会把可恢复的降级状态变成永久数据丢失。

权限问题​

Access Denied 是最常见的「不是故障的故障」。按这个顺序查:

# 1. 这个用户到底绑了什么策略
mc admin user info cluster reader
mc admin policy info cluster readwrite

# 2. 桶的匿名策略是不是被改过
mc anonymous list cluster

# 3. 用 trace 看请求落在哪个桶、哪个动作上被拒
mc admin trace -v --status-code 403 cluster

常见原因归类:

  • 密钥不对:Access Key / Secret Key 打错、用了别的环境的凭据、密钥被轮换后客户端没更新。
  • 策略不匹配:只授了 s3:GetObject 却要上传;策略里的资源写成 arn:aws:s3:::bucket 而不是 arn:aws:s3:::bucket/*,导致对象级操作被拒。
  • 前缀限制:策略限制了 photos/public/*,客户端往 photos/private/ 写当然被拒。
  • 时间偏差:签名带时间戳,服务端时间差超过 15 分钟直接拒签,错误信息常常也是 Access Denied,很有迷惑性。
  • 区域不匹配:客户端配了 us-east-1,桶实际在别的 region,部分 SDK 会报签名错误。
  • TLS 中间人:自签证书没被信任,客户端直接拒连,报错看着像认证问题。
最小权限落地

给每个业务建独立用户、独立策略,资源精确到前缀,动作精确到需要的几个。排障时先看策略 JSON,再看桶策略,最后才怀疑服务端——90% 的 Access Denied 在策略层面就能找到答案。

扩容后的数据重平衡​

扩容之后最常见的「故障」其实是误解:新池是空的,老池还是满的,容量怎么没降下来?

原因在写入路由:新对象按各池空闲空间的比例分配,已经写下的对象不会自动搬家。所以扩容后短时间内,老池的使用率不会下降。

# 看各池的容量分布
mc admin info cluster

# 手动触发重平衡,把老池的数据匀到新池
mc admin rebalance start cluster

# 看进度
mc admin rebalance status cluster

# 需要时暂停/停止
mc admin rebalance stop cluster

重平衡会大量读写磁盘,务必挑业务低峰期,并且提前确认网络带宽够用。如果只是想「让新数据写到新池」,不跑重平衡也没问题,新写入自然会往空闲的池倾斜。

重平衡不是必须的

重平衡的收益是让容量分布均匀、性能可预测,代价是一段时间的 I/O 压力。如果老池还有余量、业务对延迟敏感,可以不做,等自然增长慢慢摊平。不要在不了解影响面的情况下随手 mc admin rebalance start。

最佳实践清单​

架构与部署

  • 生产至少 4 节点 × 4 盘,EC:4;容量按两年规划,70% 水位前扩容。
  • 磁盘直通、XFS、挂载点连续编号、写进 fstab 并重启验证。
  • 全节点同一端口、同一配置、时间同步;变更时全节点同时重启,禁止滚动。
  • 前面挂负载均衡(least_conn),TLS 终结在 LB 或 MinIO 自身,二选一不要混。

安全

  • 换掉默认凭据,root 账号只用于管理,业务用独立用户 + 最小权限策略。
  • 9001 控制台不暴露公网;指标端点不开公网;证书提前 30 天续期。
  • 预签名 URL 当临时凭证对待,不发长期链接、不贴公开渠道。

数据治理

  • 版本控制只开给需要的桶,同时配非当前版本过期规则。
  • 用生命周期规则代替客户端删除脚本,临时目录必须有前缀级过期规则。
  • 给业务桶设配额,防止单桶写爆拖垮集群。

可靠性

  • 坏盘立刻换,别攒;监控离线磁盘数是第一优先级告警。
  • 纠删码不等于备份,必须有异地 mc mirror 或桶复制,且每月演练恢复。
  • 扩容前导出配置:mc admin cluster bucket export 和 mc admin cluster iam export。

变更

  • 升级前读 release notes,在测试环境验证 SDK 兼容性;mc 版本不要落后服务端太多。
  • 任何删除操作前先 mc ls --recursive 确认范围,重要数据先 mc mirror 一份。
  • 折腾集群前先把 mc admin info --json 和日志存下来,出问题才有对比基线。

小结​

  • 排障先定三件事:影响面、读写方向、是否所有客户端;开局三命令是 mc admin info、journalctl、mc admin trace。
  • 磁盘故障的处理是「换盘 → 原挂载点格式化挂载 → 重启 → heal」,影响范围限于该盘所在集合,修复期间性能下降且冗余临时降低。
  • EC:4 的 4 节点集群掉两个节点就丢数据,节点故障按 P0 处理。
  • 集群不可写优先查仲裁、时间、证书、磁盘水位;多池部署下一个池全挂会停掉整个集群的 I/O。
  • 脑裂靠「校验值等于一半时写仲裁 +1」防住,处置原则是恢复网络,不碰数据。
  • Access Denied 九成在策略和时间偏差上,用 mc admin trace --status-code 403 直接看被拒的动作。
  • 扩容后老数据不会自动迁移,需要时用 mc admin rebalance,挑低峰期做。
  • 最佳实践的核心就三句:坏盘立刻换、冗余之外还要有备份、变更全节点同时做。

系列正篇到此结束,附录里的命令速查和参考资料可以当案头手册随时翻。