上一篇 下一篇 分享链接 返回 返回顶部

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

发布人:Minchunlin 发布时间:2025-08-29 10:44 阅读量:738


凌晨 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 与压测曲线。祝你值守平安。

目录结构
全文