返回首页

SMART 磁盘故障预测实战 — 采集管道 + smartd 告警 + XGBoost 模型 + Prometheus 可视化

📅 创建于 2026-09-07 🔄 更新于 2026-09-07 📝 1792 字

来源:耕云躬行录(微信公众号)| 发布日期:2026-08-22 半年前机房一周炸了 5 块盘,RAID 重建还没跑完第二块又掉了。事后复盘发现:这 5 块盘的 SMART 数据在故障前 2-4 周就已经有明显异常——只是没人看。从那之后作者搭了一套磁盘故障预测体系(smartmontools 采集 + XGBoost 预测 + 提前换盘),跑了半年:成功预警 12 块盘,误报 3 次,漏报 0 次。本页是这套体系的完整落地过程。

一、SMART 数据是什么,怎么读

SMART(Self-Monitoring, Analysis and Reporting Technology)是硬盘固件内置的一套自检机制,持续记录磁头读写错误率、坏扇区数量、通电时间、温度等几十个指标。Linux 上用 smartmontools 读取:

# 安装
yum install -y smartmontools   # CentOS/RHEL
apt install -y smartmontools   # Debian/Ubuntu

# 查看磁盘 SMART 是否开启
smartctl -i /dev/sda
# 开启 SMART(部分盘默认关闭)
smartctl -s on /dev/sda
# 查看全部 SMART 属性
smartctl -A /dev/sda

输出示例:

ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  RAW_VALUE
 1 Raw_Read_Error_Rate     0x002f   200   200   051    Pre-fail  Always       0
 5 Reallocated_Sector_Ct   0x0033   200   200   140    Pre-fail  Always       0
 7 Seek_Error_Rate         0x002e   200   200   000    Old_age   Always       0
 9 Power_On_Hours          0x0032   044   044   000    Old_age   Always   41437
194 Temperature_Celsius     0x0022   097   091   000    Old_age   Always      50
197 Current_Pending_Sector  0x0032   200   200   000    Old_age   Always       0
198 Offline_Uncorrectable   0x0030   200   200   000    Old_age   Always       0

读表要点:

  • VALUE 是归一化值(满分通常 200 或 100),RAW_VALUE 才是原始计数——判断故障盯 RAW_VALUE
  • TYPE 列重点关注:Pre-fail 意味着这个属性是厂家认定的"故障前兆指标"

二、哪 6 个指标真正能预判故障

Backblaze 运营着 30 万块硬盘,每季度公开故障统计数据。根据他们多年的数据分析(加上作者自己的经验),真正和故障强相关的 SMART 指标就这 6 个:

ID 属性名 含义 危险信号
5 Reallocated_Sector_Ct 重映射扇区数 RAW_VALUE > 0 且持续增长
187 Reported_Uncorrectable 无法纠正的错误数 任何非零值
188 Command_Timeout 命令超时次数 突然暴增
197 Current_Pending_Sector 等待重映射的扇区 RAW_VALUE > 0
198 Offline_Uncorrectable 离线不可纠正扇区 RAW_VALUE > 0
196 Reallocated_Event_Count 重映射事件计数 持续增长

常见误解:ID 1 Raw_Read_Error_Rate 数字很大不代表盘要挂了——希捷的盘这个值正常就是几百万,它的计算方式不一样(见坑 2)。真正要盯的是上面那 6 个。

经验法则(作者原话,可直接当换盘标准用)

  • Reallocated_Sector_Ct 的 RAW 值一旦开始涨,不管涨多少,这块盘就进入"观察期"
  • 如果一周内增长超过 10 个,直接安排换盘,不要犹豫
  • Current_Pending_Sector 出现非零值,配合 Reallocated 一起涨,基本可以确认这盘活不了多久了

指标亮红后的坏道处置三步(2026-09-07 磁盘故障 runbook 补充,坏道修复细节见 linux-disk-fault-scenario-runbook 场景 4):

badblocks -sv /dev/sda > /root/badblocks.txt                       # 1. 扫描定位坏道
dd if=/dev/zero of=/dev/sda bs=4k seek=<坏道扇区> count=1 conv=noerror,sync  # 2. 强制写坏道触发 remap
fsck.ext4 -l /root/badblocks.txt -y /dev/sda1                      # 3. fsck -l 黑名单标记不再使用

⚠️ 数据库盘(MySQL/PostgreSQL)出现坏道时,优先 mysqldump / pg_dump 逻辑导出抢救数据,不要直接在坏盘上跑 fsck -y——数据错乱后无法恢复。物理损坏抢救用 ddrescue 跳坏块(ddrescue -f -n 首轮 + -r 3 深度复读),勿用裸 dd。

三、数据采集管道(bash + crontab)

光知道看哪些指标没用,得持续采集。用一个 bash 脚本配合 crontab 定时采集,数据存 CSV,后面喂给模型:

#!/bin/bash
# collect_smart.sh - 采集所有磁盘 SMART 数据
# 建议每 6 小时跑一次
TIMESTAMP=$(date +%Y-%m-%d_%H:%M:%S)
OUTPUT_DIR="/opt/smart_data"
mkdir -p ${OUTPUT_DIR}

for disk in $(lsblk -d -n -o NAME | grep -E '^sd|^nvme'); do
  DEV="/dev/${disk}"
  # 跳过不支持 SMART 的设备
  smartctl -i ${DEV} 2>/dev/null | grep -q "SMART support is: Enabled" || continue
  # 提取关键 SMART 属性
  SMART_DATA=$(smartctl -A ${DEV} 2>/dev/null)
  # 解析关键字段
  ID5=$(echo "$SMART_DATA" | awk '/Reallocated_Sector_Ct/{print $NF}')
  ID187=$(echo "$SMART_DATA" | awk '/Reported_Uncorrect/{print $NF}')
  ID188=$(echo "$SMART_DATA" | awk '/Command_Timeout/{print $NF}')
  ID197=$(echo "$SMART_DATA" | awk '/Current_Pending_Sector/{print $NF}')
  ID198=$(echo "$SMART_DATA" | awk '/Offline_Uncorrectable/{print $NF}')
  ID196=$(echo "$SMART_DATA" | awk '/Reallocated_Event_Count/{print $NF}')
  ID9=$(echo "$SMART_DATA" | awk '/Power_On_Hours/{print $NF}')
  ID194=$(echo "$SMART_DATA" | awk '/Temperature_Celsius/{print $NF}')
  # 写入 CSV
  echo "${TIMESTAMP},${disk},${ID5:-0},${ID187:-0},${ID188:-0},${ID197:-0},${ID198:-0},${ID196:-0},${ID9:-0},${ID194:-0}" \
    >> ${OUTPUT_DIR}/smart_history.csv
done

crontab 加上:

# 每 6 小时采集一次 SMART 数据
0 */6 * * * /opt/scripts/collect_smart.sh

CSV 表头:

timestamp,disk,reallocated_sector,reported_uncorrect,command_timeout,pending_sector,offline_uncorrectable,reallocated_event,power_on_hours,temperature

这个脚本跑了半年,每台机器上大概积累了几十 MB 的数据。数据量不大,但信息密度够用。

四、smartd 实时告警(兜底方案)

在模型之外,smartd 本身就能做基础告警,作为兜底:

# /etc/smartd.conf 配置示例
# 监控所有磁盘,检测到错误发邮件
DEVICESCAN -H -l error -l selftest -f \
  -m [email protected] \
  -M exec /opt/scripts/smart_alert.sh \
  -s (S/../.././02|L/../../6/03)

参数解释:

参数 作用
-H 检查 SMART 健康状态
-l error 报告错误日志变化
-l selftest 报告自检结果
-f 检查 Usage 属性故障
-m 告警邮件收件人
-M exec 触发自定义脚本(可以发企微/钉钉/飞书)
-s 自动测试计划:S/../.././02 每天凌晨 2 点跑短测试,L/../../6/03 每周六凌晨 3 点跑长测试

自定义告警脚本对接企微机器人:

#!/bin/bash
# /opt/scripts/smart_alert.sh
WEBHOOK="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
curl -s -X POST ${WEBHOOK} \
  -H 'Content-Type: application/json' \
  -d "{
    \"msgtype\": \"markdown\",
    \"markdown\": {
      \"content\": \"## ⚠️ 磁盘健康告警\n> **主机**: $(hostname)\n> **设备**: ${SMARTD_DEVICE}\n> **消息**: ${SMARTD_MESSAGE}\n> **时间**: $(date '+%Y-%m-%d %H:%M:%S')\"
    }
  }"

启动 smartd:

systemctl enable smartd
systemctl start smartd

测试告警是否正常:在 smartd.conf 的 DEVICESCAN 行加上 -M test,重启 smartd 后会立即发一封测试邮件,验证收到后记得去掉该参数再重启

五、训练 XGBoost 故障预测模型

smartd 是规则告警——属性值达到阈值才报。但很多时候盘是"慢性病",值在涨但还没过阈值,这时候需要模型来捕捉趋势。用 Backblaze 公开数据集做训练(数据从 2013 年积累到现在,几十万块盘的 SMART 记录),再把模型部署到自己的环境做推理。

5.1 下载 Backblaze 数据

# Backblaze 每季度发布数据:https://www.backblaze.com/cloud-storage/resources/hard-drive-test-data
# 下载 2024 年 Q4 数据(约 4GB 解压后)
wget https://f001.backblazeb2.com/file/Backblaze-Hard-Drive-Data/data_Q4_2024.zip
unzip data_Q4_2024.zip -d /opt/backblaze_data/

5.2 预处理与训练(disk_failure_model.py,直接能跑)

#!/usr/bin/env python3
"""
disk_failure_model.py - 基于 SMART 数据的硬盘故障预测模型
使用 Backblaze 数据集训练,XGBoost 分类器
"""
import pandas as pd
import numpy as np
from pathlib import Path
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, roc_auc_score
import xgboost as xgb
import joblib

# ========== 1. 加载数据 ==========
data_dir = Path("/opt/backblaze_data/")
dfs = []
for f in sorted(data_dir.glob("*.csv")):
    df = pd.read_csv(f, low_memory=False)
    dfs.append(df)
raw = pd.concat(dfs, ignore_index=True)
print(f"总记录数: {len(raw):,}")

# ========== 2. 特征选择 ==========
# 只保留和故障强相关的 SMART 属性
feature_cols = [
    'smart_5_raw',    # Reallocated_Sector_Ct
    'smart_187_raw',  # Reported_Uncorrectable_Errors
    'smart_188_raw',  # Command_Timeout
    'smart_197_raw',  # Current_Pending_Sector
    'smart_198_raw',  # Offline_Uncorrectable
    'smart_196_raw',  # Reallocated_Event_Count
    'smart_9_raw',    # Power_On_Hours
    'smart_194_raw',  # Temperature_Celsius
    'smart_1_raw',    # Raw_Read_Error_Rate
    'smart_7_raw',    # Seek_Error_Rate
]
# 过滤出含这些字段的记录
available_cols = [c for c in feature_cols if c in raw.columns]
df = raw[['serial_number', 'date', 'failure'] + available_cols].copy()
df[available_cols] = df[available_cols].fillna(0)
print(f"故障样本: {df['failure'].sum()}, 正常样本: {(df['failure']==0).sum()}")
print(f"故障比例: {df['failure'].mean()*100:.4f}%")

# ========== 3. 特征工程 ==========
# 添加变化率特征(模拟:用同一块盘前后记录的差值)
df = df.sort_values(['serial_number', 'date'])
for col in available_cols:
    df[f'{col}_diff'] = df.groupby('serial_number')[col].diff().fillna(0)
# 最终特征
all_features = available_cols + [f'{c}_diff' for c in available_cols]

# ========== 4. 处理类别不平衡 ==========
# 硬盘故障是极度不平衡的(故障率约 0.01-0.1%)
# 使用 scale_pos_weight 参数处理
pos_count = df['failure'].sum()
neg_count = (df['failure'] == 0).sum()
scale_ratio = neg_count / pos_count if pos_count > 0 else 1

# ========== 5. 训练模型 ==========
X = df[all_features].values
y = df['failure'].values
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
model = xgb.XGBClassifier(
    n_estimators=200,
    max_depth=6,
    learning_rate=0.1,
    scale_pos_weight=scale_ratio,
    eval_metric='aucpr',
    use_label_encoder=False,
    random_state=42
)
model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],
    verbose=50
)

# ========== 6. 评估 ==========
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
print("\n" + "="*50)
print("模型评估结果:")
print("="*50)
print(classification_report(y_test, y_pred, target_names=['正常', '故障']))
print(f"AUC-ROC: {roc_auc_score(y_test, y_prob):.4f}")

# ========== 7. 特征重要性 ==========
importance = model.feature_importances_
feat_imp = sorted(zip(all_features, importance), key=lambda x: x[1], reverse=True)
print("\nTop 10 重要特征:")
for feat, imp in feat_imp[:10]:
    print(f"  {feat}: {imp:.4f}")

# ========== 8. 保存模型 ==========
joblib.dump(model, '/opt/smart_model/disk_failure_xgb.pkl')
joblib.dump(all_features, '/opt/smart_model/feature_names.pkl')
print("\n模型已保存到 /opt/smart_model/")

三个注意点:

  • 类别不平衡问题:硬盘故障率通常不到 0.1%,直接训练模型会偏向预测"不坏"。scale_pos_weight 参数让模型对故障样本给更高权重
  • 变化率特征_diff 特征非常重要。一块盘 Reallocated_Sector 从 0 涨到 5,和另一块从 50 涨到 55,含义完全不同。模型需要看到"变化"而不仅仅是"当前值"
  • Backblaze 数据的局限:他们主要是消费级和企业级 SATA 盘,如果你用的是 SAS 盘或 NVMe,SMART 属性 ID 会不一样,需要做适配

六、部署推理服务

模型训练好了,定时跑推理。一个 Python 脚本配合 systemd timer:

#!/usr/bin/env python3
"""
predict_disk_failure.py - 读取本机 SMART 数据,用模型预测故障概率
"""
import subprocess
import json
import joblib
import numpy as np
import requests
from datetime import datetime

# 加载模型
model = joblib.load('/opt/smart_model/disk_failure_xgb.pkl')
feature_names = joblib.load('/opt/smart_model/feature_names.pkl')

# 企微 webhook(换成你自己的)
WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
THRESHOLD = 0.6  # 故障概率超过 60% 就告警

def get_smart_data(device):
    """用 smartctl 获取 SMART 数据,返回 JSON 格式"""
    result = subprocess.run(
        ['smartctl', '-A', '-j', device],
        capture_output=True, text=True
    )
    try:
        data = json.loads(result.stdout)
        attrs = {}
        for item in data.get('ata_smart_attributes', {}).get('table', []):
            attr_id = item['id']
            raw_value = item['raw']['value']
            attrs[f'smart_{attr_id}_raw'] = raw_value
        return attrs
    except (json.JSONDecodeError, KeyError):
        return None

def predict(smart_attrs, prev_attrs=None):
    """构建特征向量并预测"""
    features = []
    base_ids = ['smart_5_raw', 'smart_187_raw', 'smart_188_raw',
                'smart_197_raw', 'smart_198_raw', 'smart_196_raw',
                'smart_9_raw', 'smart_194_raw', 'smart_1_raw', 'smart_7_raw']
    # 当前值
    for col in base_ids:
        features.append(smart_attrs.get(col, 0))
    # 变化率(和上次采集比)
    for col in base_ids:
        if prev_attrs:
            diff = smart_attrs.get(col, 0) - prev_attrs.get(col, 0)
        else:
            diff = 0
        features.append(diff)
    X = np.array(features).reshape(1, -1)
    prob = model.predict_proba(X)[0][1]
    return prob

def send_alert(device, prob, smart_attrs):
    """发送企微告警"""
    msg = (
        f"## 🔴 磁盘故障预警\n"
        f"> **主机**: {subprocess.getoutput('hostname')}\n"
        f"> **设备**: {device}\n"
        f"> **故障概率**: {prob*100:.1f}%\n"
        f"> **Reallocated_Sector**: {smart_attrs.get('smart_5_raw', 0)}\n"
        f"> **Pending_Sector**: {smart_attrs.get('smart_197_raw', 0)}\n"
        f"> **Power_On_Hours**: {smart_attrs.get('smart_9_raw', 0)}\n"
        f"> **时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
        f"**建议**:尽快安排换盘,优先备份该盘数据"
    )
    requests.post(WEBHOOK, json={
        "msgtype": "markdown",
        "markdown": {"content": msg}
    })

def main():
    import os
    import json as json_lib
    # 历史数据文件(存上次的 SMART 值,用于算 diff)
    history_file = '/opt/smart_model/last_smart.json'
    prev_all = {}
    if os.path.exists(history_file):
        with open(history_file) as f:
            prev_all = json_lib.load(f)
    current_all = {}
    # 遍历所有磁盘
    result = subprocess.run(['lsblk', '-d', '-n', '-o', 'NAME'],
                            capture_output=True, text=True)
    disks = [d.strip() for d in result.stdout.strip().split('\n')
             if d.strip().startswith(('sd', 'nvme'))]
    for disk in disks:
        device = f"/dev/{disk}"
        smart_attrs = get_smart_data(device)
        if not smart_attrs:
            continue
        current_all[disk] = smart_attrs
        prev_attrs = prev_all.get(disk)
        prob = predict(smart_attrs, prev_attrs)
        print(f"[{datetime.now()}] {device}: 故障概率 {prob*100:.2f}%")
        if prob >= THRESHOLD:
            send_alert(device, prob, smart_attrs)
            print(f"  ⚠️ 已发送告警!")
    # 保存当前数据作为下次的历史
    with open(history_file, 'w') as f:
        json_lib.dump(current_all, f)

if __name__ == '__main__':
    main()

systemd timer 配置:

# /etc/systemd/system/disk-predict.service
[Unit]
Description=Disk Failure Prediction

[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /opt/scripts/predict_disk_failure.py

# /etc/systemd/system/disk-predict.timer
[Unit]
Description=Run disk prediction every 6 hours

[Timer]
OnCalendar=*-*-* 00/6:00:00
Persistent=true

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now disk-predict.timer

七、踩过的坑(4 个,全部有解法)

坑 1:NVMe 盘的 SMART 属性完全不一样

NVMe 盘不走 ATA SMART 标准,它有自己的一套健康信息,smartctl 输出格式不同:

# NVMe 盘用这个命令
smartctl -a /dev/nvme0n1
# 关键指标不同:
# - Percentage Used: 磨损百分比(SSD 寿命)
# - Media and Data Integrity Errors: 数据完整性错误
# - Critical Warning: 临界警告位

解决办法:在采集脚本里判断盘类型,分两套逻辑:

if [[ ${disk} == nvme* ]]; then
  # NVMe 走 nvme-cli 或 smartctl 的 NVMe 模式
  PUSED=$(smartctl -a /dev/${disk} | grep "Percentage Used" | awk '{print $NF}' | tr -d '%')
  MEDIA_ERR=$(smartctl -a /dev/${disk} | grep "Media and Data Integrity" | awk '{print $NF}')
else
  # SATA/SAS 走传统 SMART
  ...
fi

坑 2:希捷盘的 Raw_Read_Error_Rate

希捷盘的 ID 1 会显示几百万甚至上亿的 RAW 值。不知道这个,第一次看到 Raw_Read_Error_Rate = 83886080 会吓一跳。实际上希捷把多个计数器打包在一个 48 位字段里,低 16 位才是真正的错误数,高位是总操作数。别把这个喂给模型当"巨大错误数"。处理方法:

# 希捷盘 Raw_Read_Error_Rate 需要特殊处理
def parse_seagate_raw_read_error(raw_value):
    """希捷盘的 raw value 是复合值,低 16 位是错误数"""
    return raw_value & 0xFFFF

坑 3:模型在新盘上误报

新盘通电时间短,某些属性的初始化值可能触发模型误报。加一个简单规则:Power_On_Hours < 720(一个月以内)的盘跳过预测,只做基础规则告警

坑 4:虚拟化环境拿不到 SMART

KVM/ESXi 虚拟机里是看不到宿主机磁盘 SMART 数据的。这个脚本得部署在物理机,或者通过 BMC/iDRAC 的 API 去抓。如果是公有云 ECS,就别想了——云厂商自己做了这层。

八、半年运行效果

监控磁盘总数约 200 块(HDD + SSD 混合):

  • 成功预警:12 块盘在故障前 1-3 周被换掉
  • 误报:3 次(新盘初始化 + 希捷盘 RAW 值解析问题,修复后降为 0)
  • 漏报:0 次

真实预警案例:

时间 事件 预警提前量 结果
2 月 sda Reallocated 快速增长 提前 18 天 换盘后原盘离线测试确认坏道
3 月 sdb Pending_Sector 出现 提前 9 天 RAID 降级但无数据丢失
5 月 nvme0n1 Percentage_Used 98% 提前 21 天 SSD 寿命到期,换新
6 月 sdc Command_Timeout 暴增 提前 3 天 接口问题,换线缆解决

后续改进方向:

  • 模型定期 refit:每季度用最新数据重新训练,适应盘型变化
  • Ceph 集成:Ceph 自带的设备健康预测模块(ceph device predict-life-expectancy)用的也是类似原理,可以参考它的实现给自己的系统加强

九、Prometheus + Grafana 可视化(附配置)

smartctl_exporter 可以直接把 SMART 数据暴露成 Prometheus 指标:

# 安装 smartctl_exporter
# 从 GitHub Release 下载: https://github.com/prometheus-community/smartctl_exporter
wget https://github.com/prometheus-community/smartctl_exporter/releases/download/v0.12.0/smartctl_exporter-0.12.0.linux-amd64.tar.gz
tar xzf smartctl_exporter-0.12.0.linux-amd64.tar.gz
cp smartctl_exporter-0.12.0.linux-amd64/smartctl_exporter /usr/local/bin/

# systemd service
cat > /etc/systemd/system/smartctl-exporter.service <<'EOF'
[Unit]
Description=Smartctl Exporter
After=network.target

[Service]
ExecStart=/usr/local/bin/smartctl_exporter --smartctl.path=/usr/sbin/smartctl --web.listen-address=:9633
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now smartctl-exporter

Prometheus 配置加一行(prometheus.yml):

scrape_configs:
  - job_name: 'smartctl'
    static_configs:
      - targets: ['node1:9633', 'node2:9633', 'node3:9633']
    scrape_interval: 5m   # SMART 数据变化慢,5 分钟够了

Grafana 直接用 Dashboard ID 20204(smartctl_exporter 官方仪表板),import 就有完整的磁盘健康视图。

十、总结:四阶段体系与最小可用方案

阶段 工具 作用
数据采集 smartmontools + cron/systemd 定时读取 SMART 属性
实时告警 smartd + 企微 webhook 阈值触发立即通知
预测分析 XGBoost + Backblaze 数据 提前 1-3 周预判故障
可视化 smartctl_exporter + Prometheus + Grafana 趋势监控和仪表板

磁盘故障预测不是什么高深的东西,核心就是两步:持续采集数据 + 发现异常趋势。即使不想搞模型,单纯把 smartd 配好,加上每周看一眼 Reallocated_Sector 有没有涨,就已经能避掉 80% 的"突然死亡"了。

别等到 RAID 红灯亮了才去看日志——那时候你能做的就只剩祈祷重建跑得比第二块盘挂得快。

关联页面

页面关联点
linux-disk-fault-scenario-runbook磁盘故障场景化修复手册:指标亮红后的坏道修复三步/数据库盘先导出原则/ddrescue 抢救(本页预警体系的处置落地)
linux-disk-inspection-tools-guide磁盘排查工具速查:iostat 阈值解读 / smartctl 属性表 / lsscsi 设备列表
linux-raid-lvm-basics-guideRAID 与 LVM 基础:本文"一周炸 5 盘、重建赶不上掉盘"的场景即 RAID 降级风险
linux-disk-io-monitoring-reference磁盘 IO 监控参考:iostat/vmstat 字段详解与五指标框架
linux-hardware-info-and-ops-guide硬件信息查询命令速查(smartctl 在列)
linux-disk-io-troubleshoot磁盘 IO 排查实战:%util 陷阱与 await 真相(性能视角,与本页健康视角互补)
linux-raid5-rebuild-risk-guideRAID 5 大容量时代重建风险:URE 二次雪崩机制深挖(本文"重建还没跑完第二块又掉"场景的底层原理)