当凌晨三点的告警短信把你从睡梦中惊醒,屏幕上赫然显示着"SCSI磁盘IO超时"的红色警报,作为运维工程师的你第一反应是什么?是紧急重启服务器,还是盲目增加重试次数?其实,Linux内核早已在底层构建了一套精密的错误处理体系。今天,我们就深入内核源码,拆解从IO超时到自动恢复的全过程,让你不仅知道"怎么办",更明白"为什么"。
在scsi_decide_disposition()函数的源码中,内核定义了五种IO完成状态,它们构成了整个错误处理的决策基础:
c复制/*
* 五种可能的SCSI命令处置方式:
* SUCCESS - 完全成功
* NEEDS_RETRY - 建议重试
* ADD_TO_MLQUEUE - 重新排队等待
* FAILED - 不可恢复错误
* TIMEOUT_ERROR - 超时错误
*/
enum scsi_disposition {
SUCCESS = 0,
NEEDS_RETRY = 1,
ADD_TO_MLQUEUE = 2,
FAILED = 3,
TIMEOUT_ERROR = 4
};
每种状态触发不同的恢复策略:
| 状态类型 | 触发条件 | 典型处理方式 |
|---|---|---|
| SUCCESS | 数据完整传输 | 正常完成IO |
| NEEDS_RETRY | Sense Key显示可重试错误 | 加入重试队列 |
| ADD_TO_MLQUEUE | 临时资源不足 | 延迟重新排队 |
| FAILED | 不可恢复硬件错误 | 终止IO并报错 |
| TIMEOUT_ERROR | 命令未在时限内完成 | 触发错误处理流程 |
关键洞察:不是所有错误都会立即触发复位操作。内核采用渐进式恢复策略,先尝试轻量级修复,避免不必要的系统抖动。
当scsi_eh_scmd_add()函数被调用时,错误处理流程并不会立即启动。内核会检查三个关键条件:
scmd->allowed中的剩余重试次数scsi_device_online()确认设备是否仍在线bash复制# 通过sysfs查看SCSI设备错误统计(实际案例)
$ cat /sys/class/scsi_host/host0/statistics/io_aborted
12
$ cat /sys/class/scsi_host/host0/statistics/io_failed
3
在真实的运维场景中,我曾遇到过一个典型案例:某云存储节点频繁报IO超时,但查看错误计数器发现io_aborted持续增长而io_failed保持不变。这表明:
ehandler内核线程执行的实际恢复操作遵循"从轻到重"的升级原则,具体步骤包括:
命令级恢复(最快)
设备级恢复
总线级恢复
主机适配器级恢复(最重)
以LIBSAS驱动的sas_scsi_recover_host()为例,其恢复流程如下:
python复制def recovery_flow(sas_task):
if task_is_at_lun():
try_abort_lun() # 尝试中止LUN所有IO
elif link_issue_detected():
lldd_I_T_nexus_reset() # 重置SAS链路
else:
lldd_clear_nexus_ha() # 终极手段:重置整个控制器
经验之谈:在阿里云某次大规模故障中,我们发现过早触发主机适配器级复位反而会加剧问题。合理的做法是:
- 先监控
/proc/scsi/scsi中的设备状态- 确认多个LUN同时报错再考虑HBA复位
- 配合
echo "scsi scan-new-devices" > /proc/scsi/scsi重新扫描
Sense Key是SCSI设备返回的错误诊断信息,直接影响恢复路径选择。常见的关键值包括:
通过sg_logs工具可以获取详细的sense数据:
bash复制# 获取设备sense信息(需要sg3_utils包)
$ sg_logs --sense /dev/sdb
在腾讯云某次磁盘故障中,我们通过分析sense key发现:
这个案例告诉我们:监控sense key的变化趋势比单次值更有诊断价值。
在/etc/sysctl.conf中可调整的关键参数:
ini复制# 控制SCSI错误处理超时(单位:秒)
dev.scsi.logging_level = 1
dev.scsi.cmd_per_lun = 32
dev.scsi.io_retry_cnt = 5
推荐的生产环境监控方案:
实时指标采集:
scsi_disk_io_timeouts(Prometheus指标)scsi_eh_timeout_seconds(错误处理耗时)日志分析规则:
bash复制# 筛选关键错误日志
journalctl -k | grep -E "scsi.*error|sense key"
自动化响应策略:
某金融客户的实际调优案例:
io_retry_cnt=3,导致频繁IO失败io_retry_cnt=7 + cmd_per_lun=64根据多年运维经验,总结出SCSI IO超时的四大常见根源:
物理层问题
协议层问题
设备固件缺陷
系统配置不当
附:快速诊断流程图
code复制开始
│
├─ 检查/proc/scsi/scsi → 设备是否在线?
│ ├─ 否 → 硬件连接问题
│ └─ 是 →
│ ├─ 检查dmesg → 有sense key?
│ │ ├─ 有 → 根据key类型处理
│ │ └─ 无 →
│ │ ├─ 测试dd读写 → 超时?
│ │ │ ├─ 是 → 存储设备故障
│ │ │ └─ 否 →
│ └─ 检查host状态 → 需要复位?
在华为云某次事故复盘中发现,90%的所谓"SCSI超时"实际是: