iSCSI 多路径:multipath 提升存储可用性
通过两条独立链路配置 device-mapper multipath,理解路径策略、别名和故障切换。
单条 iSCSI 链路的可用性,取决于交换机、网线、网卡里最弱的一环。multipath 要解决的问题正是把这个单点去掉:它让同一块 LUN 上的 IO 天然拥有多条物理路径,一条断了另一条立刻顶上,应用层毫无感知。它依赖的最基础机制是:iSCSI 会话绑定在单个 TCP 连接上,同一 LUN 完全可以经多个会话同时到达主机,而内核的 device-mapper 依据 LUN 的唯一标识(WWID)把这些独立到达的路径聚合成一块逻辑盘。下面从这条因果链出发:先推导"为什么同一块盘会变成多块盘、又如何被合并回去",再给出可完整复现的安装、配置、验证与故障演练步骤。
#原理层:从"同一块 LUN 为什么变成多个 /dev/sdX"推导
#iSCSI 会话绑定单条连接,跨网卡冗余必须建立多个会话
iSCSI 基于 TCP 传输。initiator 向 target 的某个网络门户(Portal,即 IP:端口的监听点)发起 Login,建立一条会话(Session)。在绝大多数实现里,一个会话就由一条 TCP 连接承载,绑定一个确定的源 IP 与目标 Portal。这条连接上的 IO 无法凭空"分摊"到另一块网卡上——TCP 不提供链路级多路径。
所以要让两块网卡都参与 IO,只能建立两个会话:eth1 走一个网段登录 Portal1,eth2 走另一个网段登录 Portal2。而 SCSI 层的设备寻址以会话/通道为界——每个会话都会独立发现并暴露目标上的 LUN,内核为每条通道分配独立的 scsi_device。于是同一块 LUN 在主机里出现两个块设备节点:sdb、sdc。设备多出一个,不是故障,而是"两块网卡同时连接同一 LUN"的必然结果。
initiator target
+-----------------+ +----------------------+
| eth1 192.168.10.11|--- Session1--| Portal1 192.168.10.21 | 控制器 A
| eth2 192.168.20.11|--- Session2--| Portal2 192.168.20.21 | 控制器 B
+-----------------+ +----------------------+
| |
+--> sdb(Session1 发现该 LUN) |
+--> sdc(Session2 发现该 LUN) |
同一 WWID,经 device-mapper 聚合为 /dev/mapper/mpath_data#两个设备节点的共同身份:WWID
既然 sdb 与 sdc 可能是同一块盘,也可能真是两块盘,判断依据不能是设备名——sdb/sdc 是内核按扫描顺序动态分配的,重启、重新扫描、更换槽位后都会变。判断的唯一可靠依据,是设备自己报出来的身份。
SCSI 每块盘都支持 Inquiry 命令,其中 VPD 页 0x83 返回设备标识(Device Identification),常见为 NAA 格式的十六进制长串,例如 36001405a1b2c3d4e5f60718293a4b5c6d。同一 LUN 无论从哪个 Portal 进来,报的都是同一串;不同 LUN 则不同。这一串就是 WWID(World Wide Identifier),multipath 的聚合、识别、寻址完全依赖它。
sudo lsscsi # 若未安装:sudo dnf install -y lsscsi
udevadm info -q property -n /dev/sdb | grep -E 'ID_SERIAL|ID_WWN'
udevadm info -q property -n /dev/sdc | grep -E 'ID_SERIAL|ID_WWN'预期:sdb 与 sdc 的 ID_SERIAL 完全相同,证明是同一 LUN 的两条路径。
#device-mapper:按 WWID 把多条路径聚合成单一 dm 设备
内核的 device-mapper(dm)是一个"把底层块设备映射为逻辑块设备"的框架,LVM、软 RAID 都建立在它之上。dm_multipath 是其中的一个 target 类型,专门做多路径聚合:
- multipathd 守护进程扫描系统中出现的所有块设备,逐一读取 WWID;
- 凡是 WWID 相同的设备归入同一个多路径映射,生成 /dev/mapper/mpatha(配置了 alias 时为 /dev/mapper/mpath_data);
- 对上层(文件系统、LVM)来说,这个 dm 设备就是一块普通块设备,偏移与 LUN 对齐;
- IO 下发时,dm 层按照 path_selector 从当前可用的路径中选择一条实际发送。
需要强调的认知是:聚合的是"路径",不是"数据"。两条路径背后是同一份数据,冗余的是通路,不是副本。multipath 不复制数据、不做镜像、不增加容量。
#路径健康检测、故障切换与负载均衡:failover / multibus
multipathd 周期性地对每条路径发送 path_checker 指定的探测命令。配置里的 path_checker tur 使用 SCSI Test Unit Ready,兼容性最好。探活失败的路径被标记为 failed 并从可用集合中剔除;之后下发的 IO 由 dm 层自动改走其余路径,正在进行的 IO 会在允许的范围内重试,进程基本无感知。
两种常见的路径分组策略:
path_grouping_policy failover:每条路径自成一个路径组,同一时刻只有一个组 active 提供服务,其余待命。这是主备模式,一条 active、一条 standby;数据库等对 IO 延迟敏感、不希望路径切换引入乱序的场景常用。path_grouping_policy multibus:所有路径放进同一个组,配合path_selector "round-robin 0"把 IO 轮流分发到各路径,实现 active/active 的负载均衡。
failback immediate 表示故障路径恢复后立即重新加入并切回;no_path_retry 5 表示所有路径都丢失后,IO 先重试 5 次再向上返回错误——给存储恢复留时间,也给应用留出优雅处理的机会。
选择哪种策略,必须与存储控制器的实际活动模式匹配,否则会适得其反(详见"边界与坑")。
#为什么这样就能提升可用性
单会话场景:网线、网卡、交换机任一环节故障,TCP 连接中断,会话消失,LUN 脱机,文件系统立刻报错。多路径场景:multipathd 在故障发生后的探测周期内发现路径变化,IO 换路,应用无感——这是它与"备份"的本质区别:备份应对数据丢失,multipath 应对路径不可用。它解决的只是"通路"这一层,磁盘坏道、误删除、阵列整体故障都不在它的能力范围内。
#实施层:可完整复现的操作序列
#环境与前置条件
- 发行版:以下以 RHEL 8/9、CentOS Stream 等 dnf 系为例;Debian/Ubuntu 对应包名为 multipath-tools,配置文件同为 /etc/multipath.conf,服务同为 multipathd.service,命令一致。
- 网络:initiator 有两块物理网卡 eth1/eth2,分属两个隔离网段,分别可达存储的 Portal1/Portal2;有条件时使用独立 VLAN 或专用交换机隔离存储流量。
- 存储:同一 LUN 已通过两个 Portal 暴露,且映射允许 initiator 的 IQN 访问;Linux 软目标见下文 targetcli 示例,商用阵列在阵列管理界面完成等价配置。
- 记录 initiator 的 IQN(/etc/iscsi/initiatorname.iscsi)与 target 的 IQN。
#存储侧:让同一 LUN 从多个 Portal 暴露(targetcli 示例)
真正的多路径必须由存储侧配合:同一 target、同一 LUN,同时挂在两个控制器(或两块存储网卡)的 Portal 上。以 Linux targetcli 为例:
sudo targetcli
# 1. 建 block 后端(真实块设备 /dev/sdb 作为 LUN 载体)
/> backstores/block create name=disk1 dev=/dev/sdb
# 2. 创建 iSCSI target
/> iscsi/ create iqn.2026-10.example:dsa
# 3. 删除默认的 0.0.0.0 Portal,改为两个明确地址(分别对应两个控制器/网卡)
/> iscsi/iqn.2026-10.example:dsa/tpg1/portals/ delete 0.0.0.0 3260
/> iscsi/iqn.2026-10.example:dsa/tpg1/portals/ create 192.168.10.21
/> iscsi/iqn.2026-10.example:dsa/tpg1/portals/ create 192.168.20.21
# 4. 把 LUN 挂到 target(两个 Portal 共享同一个 LUN 映射)
/> iscsi/iqn.2026-10.example:dsa/tpg1/luns/ create /backstores/block/disk1
# 5. 允许 initiator 访问
/> iscsi/iqn.2026-10.example:dsa/tpg1/acls/ create iqn.2026-10.example:init
# 6. 保存配置
/> saveconfig
/> exit关键点:两个 Portal 属于同一个 tpg1、同一个 target,LUN 只在 luns/ 里映射一次。这是 initiator 端出现"同一 LUN 多条路径"的物理前提。
#会话侧:为每块网卡建立独立 iSCSI 会话(open-iscsi 示例)
sudo dnf install -y iscsi-initiator-utils
# 确认 InitiatorName 与存储侧 ACL 一致
sudo vi /etc/iscsi/initiatorname.iscsi # InitiatorName=iqn.2026-10.example:init
sudo systemctl enable --now iscsid
# 为每块网卡创建独立 iface,绑定物理网卡与源 IP
sudo iscsiadm -m iface -I eth1 --op=new
sudo iscsiadm -m iface -I eth1 --op=update --name=iface.net_ifacename --value=eth1
sudo iscsiadm -m iface -I eth1 --op=update --name=iface.ipaddress --value=192.168.10.11
sudo iscsiadm -m iface -I eth2 --op=new
sudo iscsiadm -m iface -I eth2 --op=update --name=iface.net_ifacename --value=eth2
sudo iscsiadm -m iface -I eth2 --op=update --name=iface.ipaddress --value=192.168.20.11
# 用各自的 iface 分别发现 target
sudo iscsiadm -m discovery -t sendtargets -p 192.168.10.21 -I eth1
sudo iscsiadm -m discovery -t sendtargets -p 192.168.20.21 -I eth2
# 登录全部节点
sudo iscsiadm -m node -L all
# 确认两个 Session
sudo iscsiadm -m session -P 3判定标准:出现两个 Session,各自绑定不同的 iface 与 Portal。此时 lsscsi 应看到 sdb、sdc 两块"同型号"设备,udevadm 显示相同 ID_SERIAL。到这里,多路径的原料已经备齐:两条物理通路、同一身份。
#安装并启用 device-mapper-multipath
sudo dnf install -y device-mapper-multipath
sudo mpathconf --enablempathconf --enable 会完成三件事:若 /etc/multipath.conf 不存在则创建默认配置、启用并启动 multipathd 服务、重建 initramfs(dracut),确保重启早期就有 multipath 接管。Debian/Ubuntu 对应:sudo apt install -y multipath-tools,然后 sudo systemctl enable --now multipathd,并 sudo update-initramfs -u。
#编写 /etc/multipath.conf
一份可直接落地的配置(以原稿为准,逐项说明):
defaults {
user_friendly_names yes
path_grouping_policy failover
path_selector "round-robin 0"
path_checker tur
failback immediate
no_path_retry 5
}
multipaths {
multipath {
wwid 36001405a1b2c3d4e5f60718293a4b5c6d
alias mpath_data
}
}字段含义:
path_grouping_policy failover:主备模式,一条路径活跃,另一条待命;数据库等对 IO 延迟敏感的场景常用。要两条路径同时分担流量,改成multibus。注意path_selector "round-robin 0"在 failover 模式下只有 active 组在服务,selector 对主备场景影响有限;改成 multibus 后它才真正把 IO 分发到两条路径。path_checker tur:用 Test Unit Ready 探测路径健康,兼容性好。no_path_retry 5:所有路径都断后,IO 重试 5 次再报错,给存储恢复留时间;它通过 dm 表的 queue_if_no_path 特性实现,multipath -ll的 features 列可以看到。wwid是 LUN 的唯一标识,必须用multipath -ll第一行括号里的真实值;配置里永远用 wwid 而不是设备名,因为 sdb/sdc 的名字会漂移。示例中的 wwid 需要替换成你环境里的实际值,直接照抄会导致 alias 不生效。alias mpath_data:给这块聚合盘一个稳定可读的名字,比系统生成的 mpathX 更可维护。在较新的发行版(如 RHEL 8.3 起的 multipath-tools 0.8.x)上,官方更推荐用这种方式固定别名,减少对 user_friendly_names 与 bindings 文件的依赖。
#加载配置并确认聚合
sudo systemctl enable --now multipathd
sudo multipath -r
sudo multipath -ll修改过 wwid 或 alias 后,必要时再执行 sudo multipathd reconfigure 让守护进程重读配置。multipath -ll 的正常结果应看到:
mpath_data (36001405a1b2c3d4e5f60718293a4b5c6d) dm-3 Vendor,Product
size=500G features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='round-robin 0' prio=1 status=active
| `- 4:0:0:0 sdb 8:16 active ready running
`-+- policy='round-robin 0' prio=1 status=enabled
`- 5:0:0:0 sdc 8:32 active ready running(以上为示意输出,主机号、盘号、容量以实际为准。)含义:active 表示当前活跃路径(组),failed 表示故障路径,enabled/standby 表示待命路径组。正常情况下 failover 模式应看到一条 active、一条待命,任何一条 failed 都意味着链路有问题。
#在 mpath 设备上建文件系统并挂载
关键原则:一切操作都对着 /dev/mapper/mpath_data,永远不要碰 sdb/sdc。
sudo pvcreate /dev/mapper/mpath_data
sudo vgcreate vg_data /dev/mapper/mpath_data
sudo lvcreate -l 100%FREE -n data vg_data
sudo mkfs.xfs /dev/vg_data/data
sudo mkdir -p /data
sudo blkid -s UUID -o value /dev/vg_data/data # 记下 UUID,fstab 用 UUID 而非设备名fstab 追加一行(把 UUID 换成上面 blkid 查到的真实值;_netdev 让 systemd 在网络就绪后再挂载):
UUID=9f1c0a2b-3d4e-4f5a-b6c7-8d9e0f1a2b3c /data xfs defaults,_netdev 0 0验证挂载:
sudo mount -a
findmnt /data#验证层:怎么确认配置真的生效
#常态检查
sudo multipath -ll # 聚合盘存在,路径数等于会话数,无 failed
sudo multipathd show paths # 实时路径状态表,checker 状态应为 ready
journalctl -u multipathd --since today配合 lsscsi 与 udevadm info -q property -n /dev/sdX | grep ID_SERIAL 确认各路径 WWID 一致,sudo lsmod | grep dm_multipath 确认内核模块已加载。只要路径状态、WWID、会话数三者对得上,配置就是生效的。
#故障演练:拔一根网线
这是必须做的验证,不做等于没配:
# 1. 记录当前状态
sudo multipath -ll
# 2. 断开其中一块网卡
sudo ip link set eth2 down
# 3. 观察切换
sudo multipath -ll # 断掉的那条应变为 failed,另一条接管(failover 模式)
sudo multipathd show paths
dmesg | tail
# 4. 持续 IO 无中断
dd if=/dev/zero of=/data/test bs=1M count=1024 conv=fsync && echo IO_OK
# 5. 恢复网卡
sudo ip link set eth2 up
sudo multipath -ll # failback immediate 会自动切回真正的生产演练,建议同时观察四件事:应用的 IO 请求全程无报错(dd 打印 IO_OK);数据库/业务日志无 IO 告警;journalctl -u multipathd 中路径状态变化及时(由 ready 变 failed、再由 failed 变 ready);findmnt /data 全程可访问,挂载点没有变成只读或丢失。演练结束后删除测试文件。
#边界与坑
- WWID 写错或没写:alias 不生效,设备名回落成系统生成的 mpathX,重启后漂移,fstab 跟着失联。一律从
multipath -ll抄 wwid。 - 只配了 multipath 没配会话超时:路径断了 multipath 能切,但如果 iSCSI 会话本身被判定死亡,两条路径会同时 failed。要配合会话层参数才能扛住 target 侧故障:在 /etc/iscsi/iscsid.conf 中设
node.session.timeo.replacement_timeout(单位秒,默认 120,生产可按需调大)并重启 iscsid。 - 把 iSCSI 盘直接写进 fstab 再叠 multipath:必须只挂 mapper 设备。若误在 sdb 上建了文件系统,multipath 合并后会出现"一个 LUN 两块盘、文件系统两处挂"的混乱——两个独立设备节点各有一套块层缓存,同时写入同一 LUN 的相同偏移,没有协调机制,就是双写,极易损坏文件系统元数据。
- multibus 不是所有阵列都适用:active/passive 阵列(备用控制器不处理 IO,或 ALUA 下 non-optimized 路径)硬上 multibus,IO 会被打到备用控制器,出现拒绝、超时、间歇性错误。先确认阵列是 active/active 还是 active/passive;ALUA 阵列用
prio alua配合path_grouping_policy group_by_prio效果更稳。 - 本地盘被误聚合:如果主机本地盘与存储盘出现不应有的聚合,或 multipath 把本地盘也算进了扫描范围,在 multipath.conf 的 blacklist 段按 wwid 或 devnode 排除(例如
blacklist { devnode "^sda$" })。 - initramfs 没带 multipath:重启后早期挂载阶段没有聚合,fstab 挂载失败或挂到裸设备。用 mpathconf --enable、dracut --force 或 update-initramfs -u 处理。
- 只开 multipath 不做监控:multipath 的价值恰恰在"静默",静默也意味着故障发生时可能无人察觉。配好后的第一件事就是把它纳入监控(路径数、failed 路径告警)并定期演练。
#收尾
multipath 配好之后,它应该像不存在一样安静——只有当一条链路悄悄断了、而业务毫无察觉的时候,你才知道它值多少钱。下一步建议:把"路径数变化、出现 failed 路径"纳入告警,每季度做一次拔线演练,并验证会话层 replacement_timeout 与 multipath 的配合。同时要清楚它的边界:它只解决路径层面的可用性,不解决数据可靠性——误删除、坏盘、阵列整体故障依然要靠备份、快照与冗余介质兜底。至于什么时候不该用它:存储只有单控制器、或 initiator 只有一块网卡时,multipath 没有第二条路径可聚,配置了也是伪高可用,此时应把精力放在会话超时、链路质量与备份上。
相关阅读
Related留言讨论
0 条还没有留言,来说点什么吧。