3、多路径原理:多路径I/O(MPIO)机制、路径冗余与负载均衡

3.1 为什么需要多路径:从单点故障说起

在InfiniBand网络中,一台存储服务器与一台计算节点之间,物理上往往存在多条可用的链路。例如,每个节点可能安装了两块HCA(Host Channel Adapter)卡,每块卡又连接到不同的交换机,从而形成2×2甚至更多的物理路径。然而,操作系统默认情况下只会选择其中一条路径作为主路径进行I/O传输,其余路径处于空闲状态。这种“单活”模式存在两个明显问题:一是单点故障风险——一旦主路径上的HCA、线缆或交换机端口发生故障,I/O就会中断;二是带宽利用率低——空闲路径无法分担流量,系统整体吞吐能力被限制在单条链路的带宽之内。

多路径I/O(MPIO,Multi-Path I/O)机制正是为解决上述问题而设计的。它在操作系统与SCSI/块设备层之间引入一个抽象层,将多条物理路径统一呈现为一个逻辑设备。上层应用看到的只是一个块设备(如 /dev/mpath0),而无需关心底层究竟有多少条物理链路、数据具体走了哪条路径。MPIO的核心价值可以概括为三点:

  • 路径冗余:当一条路径失效时,I/O自动切换到其他健康路径,应用无感知;
  • 负载均衡:将I/O请求分散到多条路径上,提升聚合带宽与IOPS;
  • 故障恢复:失效路径恢复后,可自动重新加入可用路径集合,无需重启或手动干预。
关键认知:MPIO不是InfiniBand独有的概念,而是SCSI体系中的通用机制。在InfiniBand环境中,SRP(SCSI RDMA Protocol)或iSER(iSCSI Extensions for RDMA)协议将SCSI命令承载于RDMA之上,MPIO层依然工作在SCSI层,因此其原理与FC、iSCSI环境中的多路径完全一致。

3.2 MPIO核心组件与路径发现流程

MPIO机制在Linux系统中的实现通常由三个层次组成:上层设备映射器(DM,Device Mapper)、中间层路径选择器以及底层SCSI子系统。以Linux下常用的 device-mapper-multipath 工具为例,其工作流程如下:

  1. 路径发现:系统启动时,multipathd守护进程扫描所有SCSI设备,识别具有相同WWID(World Wide Identifier)的多个SCSI设备——这些设备实际上指向同一存储LUN,只是通过不同HCA/端口访问。
  2. 路径分组:将相同WWID的路径归入同一个多路径映射组,生成一个逻辑设备(如 /dev/mapper/mpatha)。
  3. 路径状态监测:multipathd周期性发送SCSI TEST UNIT READY或RDMA读请求检查每条路径的健康状态,标记为 active、failed 或 disabled。
  4. I/O路由:当应用发起I/O时,DM层根据配置的路径选择策略(如round-robin、service-time)将请求分发到某条健康路径上。

下面这张图展示了双HCA、双交换机场景下MPIO的逻辑架构:

上层应用 / 文件系统 MPIO 映射层 /dev/mapper/mpatha 路径选择策略 (round-robin) 路径 A: HCA0 → SW1 SRP LUN 0 (active) 路径 B: HCA1 → SW2 SRP LUN 0 (active) HCA0 (port 1) HCA1 (port 1) InfiniBand 交换机 SW1 InfiniBand 交换机 SW2 存储目标 (SRP Target) LUN 0 / WWID: 3600...abc ✗ 链路中断模拟

图中展示了典型的双路径拓扑:主机侧两块HCA分别连接两台交换机,存储侧同样双端口接入。MPIO层将两条物理路径抽象为一个逻辑设备 mpatha。当路径B发生链路中断时,multipathd通过RDMA CM连接状态或SCSI错误检测到路径失效,将其标记为 failed,随后所有I/O自动切换到路径A,整个过程对上层文件系统完全透明。

3.3 路径选择策略与负载均衡算法

MPIO的负载均衡能力取决于路径选择策略。Linux内核中常用的策略包括:

策略名称 调度方式 适用场景 优缺点
round-robin 轮流将I/O分发到每条健康路径 各路径带宽、延迟相近 实现简单,但未考虑路径实时负载差异
service-time 根据路径历史服务时间动态加权 路径性能不对称(如不同速率HCA) 更智能,但计算开销略高
queue-length 选择当前队列长度最短的路径 高并发、突发I/O场景 响应快,但需要内核维护队列深度
failover 仅使用一条主路径,故障时切换 对延迟极度敏感、需确定性路径 无负载均衡,但行为可预测

在InfiniBand SRP环境中,由于RDMA传输本身具有极低的延迟和CPU卸载特性,round-robin 与 service-time 是最常用的两种策略。需要特别注意的是,路径切换的粒度——默认情况下,MPIO以I/O请求(request)为单位进行分发。对于大块顺序读(如数据库全表扫描),如果I/O大小超过单个RDMA消息上限,SCSI层会将其拆分为多个子请求,这些子请求可能被分发到不同路径,从而在存储端产生乱序。因此,生产环境中通常配合 blk-mq 的多队列机制,确保同一块设备的I/O在CPU核心间分散时仍能保持合理的路径亲和性。

3.4 典型故障场景与切换过程复盘

下面通过一个实际案例来理解MPIO的故障切换过程。某分布式存储集群中,计算节点通过双端口HCA连接存储阵列,配置了 round-robin 策略。某次维护中,工程师误拔了交换机SW2上连接计算节点HCA1的光模块,导致路径B中断。

故障发生后的时间线如下:

  1. T+0ms:正在路径B上传输的RDMA请求超时,SCSI层收到 DID_TIME_OUT 错误;
  2. T+50ms:multipathd守护进程通过内核事件通知检测到路径B状态变为 failed,立即将其从可用路径集合中移除;
  3. T+80ms:DM层将超时的I/O请求重新排队到路径A上重试,应用侧仅感知到轻微的延迟抖动;
  4. T+200ms:multipathd发出告警日志,同时路径B被标记为 disabled,不再参与I/O分发;
  5. T+10min:工程师更换光模块后,multipathd通过周期性探测(默认每5秒一次)发现路径B恢复,将其重新加入可用路径集合,状态变为 active。

以下为故障切换期间的关键日志片段:

kernel: scsi host4: SRP INIT: RDMA_CM_EVENT_UNREACHABLE
multipathd: mpatha: path checker failed on sdc, checker state = FAILED
multipathd: mpatha: remaining active paths: 1
multipathd: mpatha: switch to path sdb (path A) due to failed path sdc
multipathd: mpatha: sdc reinstated, path state = ACTIVE
multipathd: mpatha: path count now 2, load balancing resumed
重要提醒:MPIO的故障切换并非“零延迟”。从路径失效到I/O重试完成,通常需要数百毫秒到数秒的时间,具体取决于探测间隔、重试次数和SCSI层超时设置。对于要求极低恢复时间(RTO)的业务,应同时配置应用层的重试机制,并适当调低 checker_timeout 和 polling_interval 参数。

3.5 常见误区与设计建议

在实际运维中,工程师对MPIO的理解常存在以下误区:

  • 误区一:路径越多越好。实际上,超过4条路径后,路径选择器的开销和内核维护成本会显著增加,且存储端可能因并发乱序而性能下降。建议每LUN保持2~4条活动路径即可。
  • 误区二:所有路径必须同时工作。在部分存储阵列中,同一LUN的多个端口可能共享同一控制器资源。此时启用全部路径反而可能因控制器内部锁竞争而降低性能,应配置为 active/standby 模式。
  • 误区三:忽略路径权重差异。如果两条路径分别经过不同速率的HCA(如25Gb/s与100Gb/s),使用 round-robin 会导致慢路径成为瓶颈。此时应改用 service-time 策略,或手动设置路径权重。
  • 误区四:故障恢复后不验证路径质量。重新加入的路径可能因光模块老化、线缆松动而存在高误码率,导致I/O重试频繁。建议在multipathd配置中启用 path_checker 的持续监测,并关注 rdma_cm 事件中的重传计数。

最后,给出几条经过生产验证的设计建议:

最佳实践:
  • 在 /etc/multipath.conf 中为每个存储阵列设置独立的 wwid 别名,避免路径误分组;
  • 将 polling_interval 设置为2~5秒,兼顾故障发现速度与系统开销;
  • 启用 fast_io_fail_tmo 和 dev_loss_tmo 参数,缩短路径失效后的I/O阻塞时间;
  • 在业务低峰期主动进行路径切换演练(如手动禁用某条路径),验证MPIO配置的正确性。

理解MPIO的原理,是后续排查多路径异常的基础。当链路切换发生时,只有清楚路径发现、状态监测、I/O路由的完整链路,才能快速定位是HCA故障、线缆问题、交换机端口异常,还是multipathd配置错误导致的路径未能正确切换。