如何在香港服务器RHEL系统环境下通过dm-multipath优化SAN存储的冗余与IO路径?

凌晨 2:10,我被电话吵醒。应用团队说:数据库偶发 30~60 秒的 IO 抖动,日志里写着 I/O error, dev sdg, sector 0。位置在香港 DC2,BGP 专线稳定,但存储是新接的 SAN。白天迁移赶时间,我们只做了最小化连通测试——现在看来远远不够。
我背上工具包进机房:两台 Brocade 48 口光纤交换机(Fabric A/B),阵列是双控制器 ALUA 架构,主机是 RHEL(生产大多是 RHEL 7/8,也有兼容的 CentOS 7),双端口 16Gb FC HBA。任务很明确:用 dm-multipath 做好冗余与路径调度,稳定吞吐、拉平延迟,并完成故障演练。
1. 拓扑、版本与目标
1.1 目标
- 每个 LUN 至少 4 条有效路径(A/B Fabric × 控制器对称/非对称)。
- 失去任意一条/半边 Fabric,业务无感;路径抖动时 IOPS 平滑。
- 统一命名(可读 alias),方便 DBA/运维/监控协作。
- 选择合适的 path selector 与优先级策略(ALUA prio、service-time/round-robin)。
1.2 机型/软件清单(示例)
| 组件 | 规格/版本 | 备注 |
|---|---|---|
| 服务器 | 2×Intel Xeon Gold / 256GB RAM | 本文与 CPU 无强相关 |
| HBA | Emulex LPe16000 16Gb FC ×2 | lpfc 驱动 |
| 交换机 | Brocade 6510 ×2(Fabric A/B) | 单独 zoning |
| 阵列 | 示例:DELL EMC Unity / HPE 3PAR / Huawei OceanStor / NetApp ONTAP(任选其一) | ALUA 支持 |
| OS | RHEL 7/8/9(CentOS 7 同步参考) | 需安装 device-mapper-multipath |
| 内核 IO | blk-mq(RHEL8/9 默认) | 影响调度器选择 |
1.3 逻辑拓扑(ASCII)
[Host HBA0]====(Fabric A)====[Array Ctrl A Port 0]
| |
(LUN Paths) (ALUA)
| |
[Host HBA1]====(Fabric B)====[Array Ctrl B Port 0]
2. 前置:Zoning 与 LUN 映射核对
Zoning 的基本原则:单发单收、对称跨 Fabric。
| 组件 | 规格/版本 | 备注 |
|---|---|---|
| 服务器 | 2×Intel Xeon Gold / 256GB RAM | 本文与 CPU 无强相关 |
| HBA | Emulex LPe16000 16Gb FC ×2 | lpfc 驱动 |
| 交换机 | Brocade 6510 ×2(Fabric A/B) | 单独 zoning |
| 阵列 | 示例:DELL EMC Unity / HPE 3PAR / Huawei OceanStor / NetApp ONTAP(任选其一) | ALUA 支持 |
| OS | RHEL 7/8/9(CentOS 7 同步参考) | 需安装 device-mapper-multipath |
| 内核 IO | blk-mq(RHEL8/9 默认) | 影响调度器选择 |
现场技巧:在主机上快速确认 WWPN:
# 两种常用方式
cat /sys/class/fc_host/host*/port_name
systool -c fc_host -v | egrep -i 'node_name|port_name'
3. OS 端准备:包、服务与基础核对
3.1 安装 multipath 组件
RHEL 7/CentOS 7:
yum install -y device-mapper-multipath sg3_utils
mpathconf --enable --with_multipathd y
systemctl enable --now multipathd
RHEL 8/9(dnf):
dnf install -y device-mapper-multipath sg3_utils
mpathconf --enable --with_multipathd y
systemctl enable --now multipathd
3.2 发现 LUN(FC 环境通常热插即识别)
# 可选:手动 rescan(谨慎在生产上批量执行)
for host in /sys/class/scsi_host/host*; do echo "- - -" > $host/scan; done
lsblk -S -o NAME,TRAN,HCTL,MODEL,SIZE
3.3 基础超时与队列参数(udev 持久化)
为什么要改? 多路径切换时,单路径设备的 SCSI 超时若太短/太长都可能引发应用报错或长时间卡顿。一般把 dev_loss_tmo 与 timeout 调整到与阵列建议一致(常见 60~120 秒)。
创建 /etc/udev/rules.d/99-scsi-params.rules:
ACTION=="add|change", SUBSYSTEM=="scsi", ATTR{device/timeout}="60"
ACTION=="add|change", SUBSYSTEM=="scsi", ATTR{device/rescan}="1"
触发生效:
udevadm control --reload
udevadm trigger --subsystem-match=scsi --action=change
坑警示:不要在 multipath 生效前就用分区工具对单路径 /dev/sdX 动手,否则会留下“幽灵分区”。统一等 /dev/mapper/mpath* 或 alias 出现后再操作。
4. 设计 multipath 策略与命名
4.1 命名规范(强烈建议)
以业务/用途命名:ora_data01、pg_wal01、es_hot01。
统一放到 /dev/mapper/<alias>,并在 /dev/multipath/<alias> 建立友好链接(系统会自动维护)。
4.2 核心参数取舍
ALUA 环境:prio alua + path_checker tur。
选择器:
- service-time 0:按路径服务时间加权,在路径性能不均/阵列有优先级时更稳。
- queue-length 0:根据队列长度分配,适合相对均匀的路径。
- round-robin 0:简单轮询,适合同质路径但在抖动时可能放大尾延迟。
- 分组策略:path_grouping_policy group_by_prio(ALUA 主备优先)。
故障行为:
- no_path_retry 60:无路径时在内核层排队 60 次(约等于 60 秒);
- 或 fail_if_no_path:无路径直接失败(用于极端需要尽快失败的场景)。
- 不再推荐 永久开启 queue_if_no_path(可能造成长时间卡死)。
- find_multipaths:建议启用 yes 或 strict(新版本支持),避免误认单路径磁盘。
5. 标准配置模板(通用 ALUA + 示例阵列)
文件:/etc/multipath.conf
defaults {
user_friendly_names no
find_multipaths yes
polling_interval 5
max_fds 8192
fast_io_fail_tmo 5
dev_loss_tmo 60
}
# 厂商特性(按需开启一个,以下为常见阵列示例)
devices {
device {
vendor "DELL EMC"
product "Unity.*"
path_checker tur
path_grouping_policy group_by_prio
prio alua
hardware_handler "1 alua"
path_selector "service-time 0"
rr_min_io 100
no_path_retry 60
failback immediate
}
device {
vendor "HPE"
product "3PARdata|Primera"
path_checker tur
path_grouping_policy group_by_prio
prio alua
hardware_handler "1 alua"
path_selector "service-time 0"
rr_min_io 100
no_path_retry 60
failback immediate
}
device {
vendor "HUAWEI"
product "XSG|OceanStor.*"
path_checker tur
path_grouping_policy group_by_prio
prio alua
hardware_handler "1 alua"
path_selector "service-time 0"
rr_min_io 128
no_path_retry 60
failback immediate
}
device {
vendor "NETAPP"
product ".*LUN.*"
path_checker tur
path_grouping_policy group_by_prio
prio alua
hardware_handler "1 alua"
path_selector "service-time 0"
rr_min_io 64
no_path_retry 60
failback immediate
}
}
# 为每个 LUN 指定可读 alias(推荐)
multipaths {
multipath {
wwid 36001405f8d430001a6d6c0e7e0000012
alias ora_data01
path_selector "service-time 0"
}
multipath {
wwid 36001405f8d430001a6d6c0e7e0000013
alias ora_fra01
path_selector "service-time 0"
}
}
blacklist_exceptions {
property "(ID_WWN|ID_SERIAL)"
}
找 WWID:
# 在单路径设备出现后即可查询
/sbin/scsi_id --page=0x80 --whitelisted --device=/dev/sdX
# 或通过 multipath 命令收集(更直观)
multipath -v2 -d | awk '/^\s*wwid/ || /^\s*size/ || /^\s*vendor/ || /^\s*product/ {print}'
生效验证:
multipath -t # 仅测试配置语法
systemctl restart multipathd
multipath -ll # 查看分组、优先级、路径状态
ls -l /dev/mapper # 检查 alias
样例输出片段(理想状态):
ora_data01 (36001405f8d430001a6d6c0e7e0000012) dm-2 DELL EMC,Unity
size=2.0T features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 3:0:0:1 sdg 8:96 active ready running
`-+- policy='service-time 0' prio=10 status=enabled
`- 4:0:0:1 sdh 8:112 active ready running
解释:上组为首选(ALUA 优先级高),下组为备选;路径都在 running 状态。
6. iSCSI 场景补充(若非 FC)
安装与发现:
dnf/yum install -y iscsi-initiator-utils
systemctl enable --now iscsid
iscsiadm -m discovery -t sendtargets -p <target_ip>
iscsiadm -m node --login
绑定网卡与会话(多网口多子网时):
iscsiadm -m node -T <iqn.of.target> -p <target_ip>:3260 \
--op=update -n iface.iscsi_ifacename -v iface0
关键点:每个 iSCSI 会话走独立物理口/VLAN,阵列侧启用 MPIO/ALUA,主机端 multipath 同样按上文配置。
7. 性能优化与调优细节
7.1 选择器与参数
| 选择器 | 特点 | 适用 |
service-time 0 |
按路径响应时间动态加权,抖动时更稳 | 推荐默认(ALUA) |
queue-length 0 |
根据排队深度调度 | 队列差异明显场景 |
round-robin 0 |
简单轮询 | 路径完全同质、阵列无 ALUA 优先级 |
rr_min_io/rr_min_io_rq 建议保持 ≥64,避免过于频繁切换导致队头阻塞;failback immediate 让主路径恢复后尽快回切(与阵列策略一致)。
7.2 HBA/块层参数
确认 HBA 队列深度(常见 32/64/128),根据阵列建议与业务并发适度增减。
RHEL8/9 默认 blk-mq:/sys/block/dm-*/queue/scheduler 通常为 none;底层 sdX 常见 mq-deadline/none,无需强改。
max_sectors_kb 与阵列段大小匹配(如 1024/4096),谨慎调整,以 fio/生产负载验证为准。
7.3 同步文件系统与挂载
mkfs.xfs /dev/mapper/ora_data01
mkdir -p /u01
echo "/dev/mapper/ora_data01 /u01 xfs noatime,nodiratime,attr2 0 0" >> /etc/fstab
mount -a
8. 故障演练与可观察性
8.1 主动拉链演练
watch -n1 'multipath -ll | egrep -A2 "active|failed|fault"'
演练步骤:
- 拔掉 Fabric A 某条光纤;
- 观察 multipath -ll:应有路径转为 failed,组状态从 active→enabled,IO 继续走剩余路径;
- 插回光纤,确认自动恢复,status=active 回到主组。
8.2 multipathd 交互式诊断
echo 'show maps' | multipathd -k
echo 'show paths' | multipathd -k
journalctl -u multipathd -f
8.3 常见告警含义
- path down:物理/链路/阵列端口问题;
- map queue_if_no_path:所有路径不可用,正在排队;
- failback:主路径恢复后回切。
9. 典型踩坑与现场解法
单路径上分区/建卷:
症状:后来启用 multipath 后出现重复设备、分区表错乱。
解法:
umount /dev/sdX*
multipath -f <map|wwid>
wipefs -a /dev/sdX # 极度谨慎,确保是错误设备
rescan 后仅在 /dev/mapper/<alias> 上建分区
find_multipaths 未开 导致识别混乱:
症状:看到 mpathX 与 sdX 并存,甚至申请到了错误 LUN。
解法:显式 find_multipaths yes/strict,重启 multipathd 并重扫。
queue_if_no_path 导致业务“假死”:
症状:阵列维护时应用卡住很久。
解法:改为 no_path_retry 60 或 fail_if_no_path,并与应用超时策略对齐。
ALUA 优先级不生效:
症状:所有路径同优先级,走了非最佳控制器。
解法:确认阵列端启用 ALUA;主机 prio alua,path_checker tur;multipath -ll 应显示不同 prio 值。
WWID 变化(阵列端复制/迁移后):
症状:alias 失效、fstab 挂载失败。
解法:用新 WWID 更新 multipath.conf,保持 alias 不变;或采用 LVM PV/VG 在 multipath 之上减少直接依赖。
Boot from SAN:
要点:内核镜像需包含多路径模块,dracut --force --add multipath;内核参数包含 rd.multipath=default;做双 Fabric 演练。
10. 基准测试:从“能用”到“好用”
fio 脚本(示例):
[global]
ioengine=libaio
direct=1
time_based=1
duration=120
filename=/u01/fio.test
size=64G
numjobs=4
[seqread]
rw=read
bs=1M
[randrw]
rw=randrw
bs=4k
rwmixread=70
10.1 测试场景与结果(示例数据)
| 场景 | 选择器 | 顺序读 MB/s | 4K 混合 IOPS | 99% 延迟 (ms) |
| 单路径(对照) | - | 780 | 38,000 | 8.9 |
| 多路径×4(round-robin) | rr | 1,420 | 62,000 | 6.1 |
| 多路径×4(service-time) | st | 1,470 | 68,000 | 5.4 |
解读:service-time 在路径轻微不均衡时更抗抖,尾延迟更低;吞吐、IOPS 均优于 rr。
11. 运维清单(上线前后必做)
我把这部分扩成“可直接照抄执行”的上线清单,分为上线前(Pre‑flight)与上线后(Post‑flight),附验收标准、演练要点与回退条件。
11.1 上线前(Pre‑flight,D‑1 至 T‑0)
总则:
- 变更单已审批;窗口与影响面已广播(DBA/存储/网络/DC 值守到位)。
- 有回退方案且已在测试环境验证;必要时准备只读窗口或业务限流预案。
检查清单(逐项打钩)
| 项 | 命令/位置 | 验收标准 |
| Multipath 版本 | rpm -q device-mapper-multipath / multipathd -v |
版本符合基线(与阵列兼容列表匹配) |
| 服务状态 | systemctl is-active multipathd |
active |
| HBA WWPN | cat /sys/class/fc_host/host*/port_name |
与 Zoning 表一致(双 Fabric) |
| Fabric 健康 | (网络/存储侧)switchshow/porterrshow |
无持续 CRC/ITW 增长,端口 up |
| Zoning/Mapping | 存储控制台 | 主机对象/HostGroup 正确,LUN 已映射并启用 ALUA |
| LUN WWID 收敛 | /sbin/scsi_id … |
记录所有生产 LUN 的 WWID 清单 |
| multipath 命名 | /etc/multipath.conf |
multipaths{ alias=业务名 } 覆盖所有 LUN |
| ALUA/优先级 | multipath -ll |
主组 prio 明显高于备组;status=active/ready |
| 超时参数 | /etc/udev/rules.d/99-scsi-params.rules |
timeout>=60s,与阵列建议一致,已触发生效 |
| blk 层 | cat /sys/block/dm-*/queue/scheduler |
RHEL8/9 通常为 none;无需额外调度 |
| fstab | /etc/fstab |
仅使用 /dev/mapper/<alias>;挂载选项符合应用(如 noatime) |
| 备份 | tar czf … |
已备份 multipath.conf、udev 规则、Zoning 截图与 multipath -ll 输出 |
| 引导(如 Boot from SAN) | dracut --add multipath -f |
rd.multipath=default 生效,已做双 Fabric 引导演练 |
上架前自检脚本(可选)
mpath_ok() {
set -e
echo "== multipathd =="; systemctl is-active multipathd
echo "== maps =="; multipath -ll | egrep -A2 'policy|prio|status' || true
echo "== fstab =="; egrep -v '^#|^$' /etc/fstab | egrep 'mapper'
}
mpath_ok
故障切换演练(强制)
- 拔掉 Fabric A 某条上联或 HBA 口;
- multipath -ll 应出现一组路径 failed,IO 继续走备组;
- 插回后观察 failback immediate 是否回切至主组;
- 重复对 Fabric B;记录演练截图存档。
验收标准(硬性)
- 每个生产 LUN ≥ 2 组(主/备)且每组 ≥ 1 条 active ready 路径;
- multipath -ll 中无 faulty/shaky/持续 flap ;
- FIO 5~10 分钟抽测:顺序读吞吐接近阵列规格,99% 延迟稳定,无明显抖动;
- 业务预发布读写验证通过(DB/中间件无 I/O 错误)。
回退触发条件(任一满足即回退)
- 演练中出现 I/O 长卡顿(> 30s)且不可解释;
- 路径 flap > 3 次/10 分钟;
- 99% 延迟较基线恶化 > 50% 且恢复无望;
- 关键业务自检失败(库无法打开/日志报 I/O 错误)。
11.2 上线后(Post‑flight,T+0 ~ T+7 天)
T+0 ~ 30 分钟(窗口内)
- 观察面板:dm-* 设备 IOPS/Latency、path down 告警。
- journalctl -u multipathd -n 200 | egrep -i 'fail|path|map' 无新增错误。
- 核查 multipath -ll 主备组与预期一致。
T+1 小时
- 业务侧:DB AWR/pg_stat/慢查询分位回到或优于基线;
- 基础侧:iostat -x 1 10 dm-* 观察 r_await/w_await 稳定;
- 存储侧:端口错误计数无异常增长(由存储同事确认)。
T+24 小时
- 汇总 99/99.9 分位,峰值时段无异常尖刺;
- 对比 cutover 前后 24h 的 P95/P99(保留图表与多路径日志)。
T+7 天
退出加护期;固化 SLO、阈值与巡检项;归档变更材料。
监控与告警阈值(建议)
| 指标 | 阈值(建议) | 行动 |
dm-* 设备 99% 读/写延迟 |
> 2× 基线、持续 5 分钟 | 存储+系统联合排查 |
| 失败路径数量 | ≥ 1 条,持续 > 60s | 网络/存储联动检查链路与端口 |
| 路径 flap 次数 | > 3 次/10 分钟 | 定位光模块/跳线/端口健康 |
| 非优化路径承载比例(ALUA) | > |
变更记录模板(留痕)
变更编号:
时间窗口:
参与人:系统/存储/网络/DBA
涉及主机:
涉及 LUN/WWID:
关键配置:/etc/multipath.conf(版本/差异)
演练结果:截图/命令输出链接
FIO 抽测:吞吐/IOPS/延迟(基线 vs 现状)
监控对比:P95/P99(前后 24h)
结论与建议:
最小化回退步骤(参考)
- 停止高写入业务或切只读;
- umount 相关文件系统;
- 存储侧取消多路径映射或主机侧临时禁用 map:multipath -f <alias|wwid>(谨慎);
- 按原单路径(或旧映射)恢复挂载验证;
- 记录原因并安排复盘(链路/参数/阵列端)。
12. FAQ:RHEL/CentOS 版本差异要点
RHEL7/CentOS7:yum 包管理;blk-mq 在高版本内核更成熟;部分 find_multipaths 模式可选项较少。
RHEL8/9:全面 blk-mq;service-time 与 ALUA 表现更稳定;建议用 dnf 并关注 multipath-tools 版本差异。
命令兼容性:mpathconf、multipathd -k、scsi_id 在两个大版本基本一致。
13. 收尾:凌晨 4:35 的那杯咖啡
回到监控大屏时,数据库的 99% 延迟已经稳在 5~6ms,颜色从橙变绿。我又做了最后一次拉链——A Fabric 全断。应用曲线只是轻轻抖了一下,像海面上被风拨动的光斑,很快又平了。
凌晨 4:35,我端着咖啡在机房旁的休息区坐下,记录下这篇复盘。dm-multipath 并不神秘,它只是把“通路”这件事做得更像工程:有策略、有观测、有预案。
等天亮,应用团队会看到一夜之间消失的红点,而你,也可以照着这份清单把你的 SAN 路打通、打稳、打漂亮。
附:一键收集诊断脚本(可直接用)
#!/usr/bin/env bash
set -euo pipefail
OUT=/tmp/mpath_diag_$(date +%F_%H%M%S)
mkdir -p "$OUT"
{
echo "== uname -a =="; uname -a
echo "\n== HBA WWPN =="; cat /sys/class/fc_host/host*/port_name || true
echo "\n== lsblk -S =="; lsblk -S -o NAME,TRAN,HCTL,MODEL,SIZE
echo "\n== multipath -ll =="; multipath -ll || true
echo "\n== multipath.conf =="; cat /etc/multipath.conf || true
echo "\n== udev rules =="; grep -R "scsi" /etc/udev/rules.d || true
echo "\n== dmesg multipath =="; dmesg | egrep -i 'dm-|multipath|scsi' | tail -n 200
} > "$OUT/summary.txt"
tar czf "$OUT.tgz" -C /tmp "$(basename "$OUT")"
echo "Collected: $OUT.tgz"
最后提示:任何厂商阵列都有“微调”建议(比如 rr_min_io、dev_loss_tmo、ALUA 模式),现场以阵列官方推荐为准。上文模板足以覆盖 90% 的常见生产情境,剩下 10% 靠你手里的 multipath -ll 与压测曲线。祝你值守平安。