最近我们生产环境经历了一次真实的磁盘故障,让我深刻体会到分布式存储系统容错能力的重要性。今天就把这次RustFS磁盘故障的完整处理过程分享给大家,包括从故障检测到数据恢复的全流程。
事故背景:凌晨3点的紧急告警
那天凌晨3:15,监控系统突然告警:
-
RustFS节点
storage-node-03磁盘I/O错误率飙升 -
系统日志出现
I/O error on dev sdb报错 -
该节点承载了集群15%的数据量
我们的硬件环境:
-
6节点RustFS集群
-
每节点12块10TB HDD(总共720TB裸容量)
-
纠删码配置:4+2(允许同时坏2块盘)
第一步:快速诊断与确认故障
1.1 系统层面检查
# 查看系统日志,确认故障磁盘
tail -f /var/log/syslog | grep -i error
# 输出:kernel: [123456.789012] blk_update_request: I/O error, dev sdb, sector 123456789
# 检查磁盘SMART状态
smartctl -a /dev/sdb
# 关键指标:Reallocated_Sector_Ct(重映射扇区数)已超过阈值
1.2 RustFS集群状态检查
# 查看集群整体状态
rustfs-admin cluster status
# 输出显示:node-03 有一个磁盘处于 degraded 状态
# 检查具体磁盘状态
rustfs-admin disk list --node node-03
# 输出:/dev/sdb (DISK05) status: FAILED, last error: I/O timeout
1.3 业务影响评估
# 检查当前读写操作是否受影响
rustfs-admin metrics get --metric io_requests
# 输出显示:读请求错误率从0.01%上升到0.5%,但写操作正常
# 确认数据安全性
rustfs-admin heal status --summary
# 输出:数据完整性99.8%,有2个对象需要修复
第二步:安全卸载故障磁盘
2.1 停止相关服务
# 先停止RustFS服务,但要注意策略
# 如果是单磁盘故障,且集群有冗余,可以不用停服务
# 但我们选择保守方案:先停止该节点的RustFS服务
# 在故障节点上执行
systemctl stop rustfs-server
# 确认服务已停止
systemctl status rustfs-server
2.2 卸载磁盘
# 卸载故障磁盘
umount /mnt/disk05
# 如果提示设备忙,查找占用进程
lsof /mnt/disk05
# 如果有进程占用,逐个kill或使用fuser
fuser -km /mnt/disk05 # 强制终止占用进程
umount /mnt/disk05
# 确认卸载成功
df -h | grep disk05 # 应该没有输出
第三步:物理更换磁盘
3.1 硬件操作记录
# 记录更换前信息(用于后续审计)
echo "=== 磁盘更换记录 ===" > /tmp/disk_replacement.log
echo "时间: $(date)" >> /tmp/disk_replacement.log
echo "故障磁盘: /dev/sdb (SN: WD-WX12A8412345)" >> /tmp/disk_replacement.log
echo "新磁盘: /dev/sdb (SN: WD-WX12A8467890)" >> /tmp/disk_replacement.log
# 物理操作:热插拔更换磁盘
# 注意:确保机房人员有防静电措施
3.2 新磁盘识别和准备
# 重新扫描SCSI总线,让系统识别新磁盘
echo 1 > /sys/class/scsi_host/host2/scan
# 确认新磁盘被识别
lsblk | grep sdb
# 输出:sdb 8:16 0 10T 0 disk
# 格式化新磁盘(保持与原有配置一致)
mkfs.ext4 /dev/sdb -L DISK05 -m 0 -T largefile4
# 验证文件系统
fsck.ext4 -f /dev/sdb
第四步:重新挂载和配置
4.1 更新挂载配置
# 检查原有的fstab配置
grep disk05 /etc/fstab
# 输出:LABEL=DISK05 /mnt/disk05 ext4 defaults,noatime,nodiratime 0 2
# 由于我们使用LABEL,fstab无需修改
# 但如果使用UUID,需要更新:
blkid /dev/sdb
# 输出:/dev/sdb: LABEL="DISK05" UUID="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
# 挂载新磁盘
mount /mnt/disk05
# 验证挂载
df -h /mnt/disk05
# 输出:Filesystem Size Used Avail Use% Mounted on
# /dev/sdb 10T 0 10T 0% /mnt/disk05
4.2 恢复RustFS服务
# 重新启动RustFS服务
systemctl start rustfs-server
# 监控服务启动日志
journalctl -u rustfs-server -f --since "5 minutes ago"
# 等待服务完全启动(约2-3分钟)
sleep 180
# 验证节点状态
rustfs-admin node status node-03
# 输出:Status: Online, Disks: 11/12 OK, 1/12 Healing
第五步:触发数据愈合
5.1 手动触发愈合过程
# 查看需要愈合的对象
rustfs-admin heal status --node node-03 --disk disk05
# 输出:Pending objects: 15, Healed objects: 0, Failed: 0
# 开始愈合过程
rustfs-admin heal start --node node-03 --disk disk05 --background
# 监控愈合进度
watch -n 10 'rustfs-admin heal status --node node-03 --disk disk05'
5.2 实时监控愈合状态
我写了一个监控脚本,实时显示愈合进度:
#!/bin/bash
# heal_monitor.sh - 实时监控数据愈合进度
HEAL_NODE="node-03"
HEAL_DISK="disk05"
echo "开始监控数据愈合过程..."
echo "节点: $HEAL_NODE, 磁盘: $HEAL_DISK"
echo "========================================"
while true; do
# 获取愈合状态
STATUS=$(rustfs-admin heal status --node $HEAL_NODE --disk $HEAL_DISK --json)
PENDING=$(echo $STATUS | jq '.pending_objects')
HEALED=$(echo $STATUS | jq '.healed_objects')
FAILED=$(echo $STATUS | jq '.failed_objects')
SPEED=$(echo $STATUS | jq '.heal_speed_objects_per_sec')
# 计算进度百分比
if [ $PENDING -gt 0 ]; then
PROGRESS=$((HEALED * 100 / (HEALED + PENDING)))
else
PROGRESS=100
fi
# 显示进度条
BAR=$(printf "%-50s" | tr ' ' '=')
BAR=${BAR:0:$((PROGRESS / 2))}
echo -ne "进度: [${BAR}] ${PROGRESS}% | 已修复: ${HEALED} | 剩余: ${PENDING} | 速度: ${SPEED} 对象/秒\r"
# 检查是否完成
if [ $PENDING -eq 0 ] && [ $FAILED -eq 0 ]; then
echo -e "\n愈合完成!"
break
fi
sleep 10
done
第六步:愈合过程优化和问题解决
6.1 遇到的性能问题
问题:愈合初期速度很慢(约50对象/秒),预计需要6小时完成。
分析原因:
# 检查系统资源
iostat -x 1 5
# 发现磁盘利用率100%,但吞吐量很低
# 检查网络带宽
iftop -i bond0
# 网络带宽使用率只有10%
解决方案:调整愈合参数
# 提高愈合并发度
rustfs-admin config set heal.concurrent_operations 16
# 调整I/O调度策略
echo deadline > /sys/block/sdb/queue/scheduler
# 限制愈合带宽,避免影响业务(可选)
rustfs-admin config set heal.max_bandwidth 500MB
优化后效果:速度提升到200对象/秒,1.5小时完成愈合。
6.2 业务影响监控
在愈合过程中,我们密切监控业务影响:
# 监控业务延迟
rustfs-admin metrics get --metric request_duration --period 5m
# 监控错误率
rustfs-admin metrics get --metric error_rate --period 5m
# 监控客户端感知的可用性
#!/bin/bash
# 客户端健康检查脚本
while true; do
START_TIME=$(date +%s%N)
curl -s -o /dev/null -w "%{http_code}" http://rustfs-cluster:9000/health
END_TIME=$(date +%s%N)
DURATION=$((($END_TIME - $START_TIME)/1000000))
echo "$(date): HTTP_STATUS, Duration: ${DURATION}ms" >> /var/log/rustfs_health_check.log
sleep 30
done
恢复结果和数据分析
愈合完成后的验证
# 最终状态检查
rustfs-admin heal status --node node-03 --disk disk05 --detailed
# 输出:
# Total objects: 1,200,000
# Healed objects: 1,200,000
# Failed objects: 0
# Healing duration: 1小时28分钟
# 数据完整性验证
rustfs-admin data verify --node node-03 --disk disk05
# 输出:All data verified successfully
性能影响统计
| 时间段 | 业务延迟 | 错误率 | 用户影响 |
|---|---|---|---|
| 故障发生 | +15% | 0.5% | 轻微感知 |
| 磁盘更换 | +5% | 0.1% | 几乎无感 |
| 数据愈合 | +8% | 0.2% | 轻微感知 |
| 恢复后 | 正常水平 | 0.01% | 无影响 |
时间线总结
-
03:15:故障检测和确认
-
03:25:服务停止和磁盘卸载
-
03:40:物理磁盘更换完成
-
03:50:新磁盘挂载和服务恢复
-
03:55:数据愈合开始
-
05:23:数据愈合完成
-
05:30:全面验证通过
总停机时间:30分钟(实际业务影响时间)
数据恢复时间:1小时28分钟(后台自动完成)
经验总结和最佳实践
成功经验
-
监控预警系统:提前15分钟发现异常,为处理赢得时间
-
标准化操作流程:按照文档步骤执行,避免人为错误
-
业务影响最小化:通过后台愈合,确保业务连续性
改进措施
基于这次经验,我们实施了以下改进:
-
增强监控:增加磁盘预测性故障检测
# 定期检查磁盘健康度
#!/bin/bash
for disk in /dev/sd{b..m}; do
REALLOC=$(smartctl -a $disk | grep Reallocated_Sector_Ct | awk '{print $10}')
if [ $REALLOC -gt 100 ]; then
echo "警告: $disk 重映射扇区数过高: $REALLOC" | mail -s "磁盘预警" admin@company.com
fi
done
-
自动化脚本:编写自动化磁盘更换脚本
-
定期演练:每季度进行一次故障恢复演练
给同行的建议
-
一定要配置冗余:我们使用的4+2纠删码在这次故障中发挥了关键作用
-
完善监控体系:不仅要监控服务状态,还要监控硬件健康度
-
建立标准化流程:避免在紧急情况下出现操作失误
-
定期测试恢复流程:确保在真实故障时能够快速响应
这次故障处理让我们对RustFS的可靠性有了更大信心。分布式存储系统的价值不仅在于性能,更在于这种"无感"的故障恢复能力。
以下是深入学习 RustFS 的推荐资源:RustFS
官方文档: RustFS 官方文档- 提供架构、安装指南和 API 参考。
GitHub 仓库: GitHub 仓库 - 获取源代码、提交问题或贡献代码。
社区支持: GitHub Discussions- 与开发者交流经验和解决方案。
希望我们的实战经验对大家有所帮助!

被折叠的 条评论
为什么被折叠?



