Skip to the content.

multipath

device mapper multipath

multipath 聚合的前提是:这些路径指向同一个存储对象。 Linux 通过 WWID(World Wide Identifier)来识别:

双路径测试盘

两个独立 virtio-scsi 控制器 (各带 iothread mp_io1/mp_io2), scsi-hd 用相同 serial=MULTIPATH, guest 内 WWID 相同,multipathd 聚合为一个 mpath 设备

guest 内使用:

sudo mpathconf --enable
sudo systemctl start multipathd
sudo multipath        # 首次需要手动触发建图
sudo multipath -ll    # 验证 mpatha 聚合了两个 virtio-scsi 的两条路径
🧀  sudo multipath -ll
mpatha (0QEMU_QEMU_HARDDISK_MULTIPATH) dm-1 QEMU,QEMU HARDDISK
size=25G features='0' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=1 status=active
| `- 2:0:0:0 sdd 8:48 active ready running
`-+- policy='service-time 0' prio=1 status=enabled
  `- 3:0:0:0 sde 8:64 active ready running

🧀  sudo multipathd show paths format "%d %D %t %T %s"
dev dev_t dm_st  chk_st vend/prod/rev
sdb 8:16  undef  undef  QEMU,QEMU HARDDISK,2.5+
sdc 8:32  undef  undef  QEMU,QEMU HARDDISK,2.5+
sdd 8:48  active ready  QEMU,QEMU HARDDISK,2.5+
sde 8:64  active ready  QEMU,QEMU HARDDISK,2.5+
sda 8:0   undef  undef  Linux,scsi_debug,0191

故障注入(host 侧):SIGSTOP/SIGCONT 对应路径的 qemu-nbd 进程即可单独卡死/恢复该路径:

kill -STOP $(pgrep -f 'qemu-nbd.*mpath1.nbd')   # 卡死路径 1
kill -CONT $(pgrep -f 'qemu-nbd.*mpath1.nbd')   # 恢复

kill -STOP $(pgrep -f 'qemu-nbd.*mpath2.nbd')   # 卡死路径 2
kill -CONT $(pgrep -f 'qemu-nbd.*mpath2.nbd')   # 恢复
# guest 内运行:持续对 mpatha 做 direct 写,每个 dd 256MiB,记录每轮耗时
#!/usr/bin/env bash
set -u
i=0
while true; do
	i=$((i + 1))
	start=$(date +%s)
	dd if=/dev/zero of=/dev/mapper/mpatha bs=1M count=256 oflag=direct status=none 2>/dev/null
	rc=$?
	end=$(date +%s)
	echo "$(date '+%T') round=$i rc=$rc elapsed=$((end - start))s"
	sleep 1
done

然后就会发现 io 是一直都卡在这里:

# sudo cat /proc/5708/stack
[sudo] password for martins3:
[<0>] bio_await+0x94/0xe0
[<0>] submit_bio_wait+0x1a/0x30
[<0>] __blkdev_direct_IO_simple+0x154/0x280
[<0>] blkdev_write_iter+0x228/0x350
[<0>] vfs_write+0x24f/0x5c0
[<0>] ksys_write+0x7b/0xf0
[<0>] do_syscall_64+0xcf/0x630
[<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e

执行 sudo multipath -ll 同样卡在这里了:

# sudo cat /proc/10128/stack
[sudo] password for martins3:
[<0>] do_read_cache_folio+0x29f/0x3d0
[<0>] scsi_bios_ptable+0x28/0xa0
[<0>] scsi_partsize+0x1f/0x140
[<0>] scsicam_bios_param+0x1b/0x170
[<0>] sd_getgeo+0xc3/0xd0
[<0>] blkdev_ioctl+0x186/0x1320
[<0>] __x64_sys_ioctl+0x4f7/0xa10
[<0>] do_syscall_64+0xcf/0x630
[<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e

不知道为什么 device mapper 关于 io 没有报错的。

nvme multipath

NVMe 支持 multipath,核心原因是:同一个存储 namespace 可能通过多条独立路径访问。 Multipath 用来把这些路径合并成一个可靠的块设备,并负责故障切换或负载均衡。

实验

qemu 启动参数:

	-drive file=/home/martins3/data/hack/vm/yyds-collei/img/nvme1,format=qcow2,if=none,id=nvme_mpath,discard=unmap \
	-device nvme-subsys,id=nvme-subsys-0,nqn=subsys0 \
	-device nvme,serial=deadbeef,subsys=nvme-subsys-0,id=nc1 \
	-device nvme,serial=deadbeef,subsys=nvme-subsys-0,id=nc2 \
	-device nvme-ns,drive=nvme_mpath,bus=nc1,nsid=1,shared=on \
lrwxrwxrwx - root 19 Jul 15:17 nvme0c0n1 -> ../devices/pci0000:00/0000:00:04.0/nvme/nvme0/nvme0c0n1
lrwxrwxrwx - root 19 Jul 15:17 nvme0c1n1 -> ../devices/pci0000:00/0000:00:05.0/nvme/nvme1/nvme0c1n1
lrwxrwxrwx - root 19 Jul 15:17 nvme0n1 -> ../devices/virtual/nvme-subsystem/nvme-subsys0/nvme0n1

所以,也就是 qemu 内部模拟了多个 channel ,最后 io 还是落入到一个盘上的。

io 策略

🧀  cat /sys/class/nvme-subsystem/nvme-subsys0/iopolicy
numa
@[
    nvme_ns_head_submit_bio+5
    __submit_bio+132
    submit_bio_noacct_nocheck+345
    blkdev_direct_IO.part.0+575
    blkdev_write_iter+427
    io_write+290
    io_issue_sqe+96
    io_submit_sqes+507
    __do_sys_io_uring_enter+1471
    do_syscall_64+59
    entry_SYSCALL_64_after_hwframe+110
]: 1365299
  nvme_subsystem
    ├── ctrl A
    │    └── nvme_ns A ──┐
    ├── ctrl B           │
    │    └── nvme_ns B ──┼── nvme_ns_head
    └── ctrl C           │       └── 聚合 gendisk: nvmeXnY
         └── nvme_ns C ──┘

策略 行为 关键特点 ━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ numa 选择距离当前 CPU NUMA node 最近的 path 默认策略;按 node 缓存路径 ───────────── ──────────────────────────────────────── ─────────────────────────────────────────────── round-robin 在同一 ANA 优先级的路径间轮转 不会为了轮转而从 optimized 切到 non-optimized ───────────── ──────────────────────────────────────── ─────────────────────────────────────────────── queue-depth 选择活动请求数最少的 controller 统计的是 controller 级 in-flight 数量

其他类型的 multipath

  1. mptcp : 多个网络路径的 tcp 来加速带宽
  2. multifd qemu migration : 多个 fd 来加速传输

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。