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;
- 故障恢复:失效路径恢复后,可自动重新加入可用路径集合,无需重启或手动干预。
3.2 MPIO核心组件与路径发现流程
MPIO机制在Linux系统中的实现通常由三个层次组成:上层设备映射器(DM,Device Mapper)、中间层路径选择器以及底层SCSI子系统。以Linux下常用的 device-mapper-multipath 工具为例,其工作流程如下:
- 路径发现:系统启动时,multipathd守护进程扫描所有SCSI设备,识别具有相同WWID(World Wide Identifier)的多个SCSI设备——这些设备实际上指向同一存储LUN,只是通过不同HCA/端口访问。
- 路径分组:将相同WWID的路径归入同一个多路径映射组,生成一个逻辑设备(如
/dev/mapper/mpatha)。 - 路径状态监测:multipathd周期性发送SCSI TEST UNIT READY或RDMA读请求检查每条路径的健康状态,标记为
active、failed或disabled。 - I/O路由:当应用发起I/O时,DM层根据配置的路径选择策略(如round-robin、service-time)将请求分发到某条健康路径上。
下面这张图展示了双HCA、双交换机场景下MPIO的逻辑架构:
图中展示了典型的双路径拓扑:主机侧两块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中断。
故障发生后的时间线如下:
- T+0ms:正在路径B上传输的RDMA请求超时,SCSI层收到
DID_TIME_OUT错误; - T+50ms:multipathd守护进程通过内核事件通知检测到路径B状态变为
failed,立即将其从可用路径集合中移除; - T+80ms:DM层将超时的I/O请求重新排队到路径A上重试,应用侧仅感知到轻微的延迟抖动;
- T+200ms:multipathd发出告警日志,同时路径B被标记为
disabled,不再参与I/O分发; - 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
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配置错误导致的路径未能正确切换。