CentOS 7多路径存储配置与性能调优实战指南
2026/9/19 18:00:06 网站建设 项目流程

1. 项目背景与核心需求拆解

1.1 为什么单路径存储会成为生产环境的隐患

很多运维同行第一次接触多路径存储,往往是在一次故障之后。服务器上挂载了一块来自磁盘阵列的LUN,系统识别为/dev/sdb,业务跑得好好的,某天机房网络抖动或者HBA卡固件升级,重启之后发现设备名变成了/dev/sdc,挂载脚本直接报错,数据库起不来。更麻烦的是,有些场景下同一条链路被操作系统识别成两个甚至四个块设备,应用层看到的是"多块盘",实际上指向的是同一份数据,一旦同时写入,文件系统直接损坏。

这个问题的根源在于:服务器到存储之间通常存在多条物理链路。以典型的双控存储为例,每台服务器配两块HBA卡,分别接到两台光纤交换机,存储的两个控制器各出一个端口,这样服务器到同一块LUN之间就有 2×2=4 条可达路径。操作系统默认的块设备层并不理解"这些路径其实通向同一个后端卷",它只会老老实实把每条路径都枚举成一个SCSI设备。于是就有了上面说的设备名漂移和重复识别问题。

Multipath(多路径)要解决的就是这件事:把这些物理上分离、逻辑上同源的路径聚合成一个虚拟块设备,向上层屏蔽底层链路的复杂性,同时提供故障切换和负载均衡能力。CentOS 7 自带的device-mapper-multipath就是干这个的,它工作在块设备层,位于 SCSI 层和文件系统层之间,对上层应用完全透明。

1.2 这套方案适合谁、解决什么问题

这篇文章面向的是手里有真实存储环境、需要在 CentOS 7 上把多路径跑起来并且跑好的运维工程师和系统管理员。如果你只是用虚拟机做实验,也能跟着走一遍流程,但很多参数调优的体感只有在真实负载下才明显。

具体来说,Multipath 在 CentOS 7 上要达成的目标有这么几个:

  • 设备聚合:把多条路径合并成/dev/mapper/mpathX这样的单一设备,业务只认这一个名字,重启、换卡、换交换机端口都不影响。
  • 故障切换:某条链路断了,I/O 自动切到其他可用路径,业务基本无感知。
  • 负载均衡:多条健康路径同时分担 I/O,提升吞吐。
  • 路径管理:提供命令行工具查看每条路径的状态,方便排障。

需要提前说清楚的是,Multipath 本身不产生冗余,冗余是存储和网络层面已经做好的,Multipath 只是把这份冗余"用起来"。如果后端只有一条物理链路,配了 Multipath 也没有意义。

1.3 核心组件与工作模型

理解 Multipath 的工作模型,关键要分清三个层次:

层次名称作用
物理层路径(path)每条 HBA 到存储端口的链路,对应一个/dev/sdX
聚合层路径组(path group)优先级相同的路径集合,同一时刻只有一个组处于 active
设备层多路径设备(mpath)对上层暴露的虚拟块设备,如/dev/mapper/mpatha

内核里的dm-multipath模块负责实际的 I/O 转发,用户态的multipathd守护进程负责监控路径状态、执行切换策略、响应配置变更。两者通过 device-mapper 的 ioctl 接口通信。multipath命令是一次性的配置和查询工具,multipathd是常驻服务,实际生产里真正干活的是后者。

提示:很多人配完 Multipath 发现不生效,八成是multipathd没起来,或者配置文件语法有问题导致守护进程加载了默认配置。排查时先看systemctl status multipathd

2. 环境准备与安装配置全流程

2.1 安装前的环境确认清单

动手之前,先把下面这些信息确认清楚,能省掉后面大量的返工:

  • 存储侧:确认 LUN 已经映射给这台服务器,并且存储管理员告诉你这块 LUN 的 WWID(World Wide Identifier)。这个 ID 是 Multipath 聚合路径的唯一依据,必须准确。
  • 链路侧lspci | grep -i fibre确认 HBA 卡被识别;cat /sys/class/fc_host/host*/port_name查看每块 HBA 的 WWPN。
  • 系统侧uname -r看内核版本,CentOS 7 建议 3.10.0-957 以上;rpm -qa | grep device-mapper确认基础包在。
  • 网络侧:如果是 iSCSI,确认iscsiadm能发现目标;如果是 FC,确认fdisk -l能看到多块同名容量的盘。

一个很实用的判断方法:如果lsblk或者fdisk -l里出现了多块容量完全一致、型号也一致的盘,而你又只申请了一块 LUN,那基本可以确定是多路径没配导致的重复识别。

2.2 安装 device-mapper-multipath

CentOS 7 的安装很直接,但有几个细节要注意:

# 确认仓库可用 yum repolist # 安装核心包和工具 yum install -y device-mapper-multipath device-mapper-multipath-libs # 确认版本 rpm -qa | grep multipath

如果生产环境不能连外网,需要提前把 rpm 包和依赖下载好。依赖关系其实不复杂,主要是device-mapperdevice-mapper-libskmod这几类。离线安装时用yum install --downloadonly --downloaddir=/tmp/mp在一台能上网的同版本机器上把包拉全,再拷到目标机yum localinstall *.rpm

安装完成后不要急着启动,先把配置文件准备好。CentOS 7 默认会生成一个/etc/multipath.conf,但内容基本是注释,实际生效的是内置默认值。我习惯的做法是保留一份原始备份,然后自己写一份精简的配置。

2.3 生成并理解默认配置

# 备份原始配置 cp /etc/multipath.conf /etc/multipath.conf.bak # 生成一份带默认值的配置参考 mpathconf --enable --with_multipathd y

mpathconf这个工具会帮你把服务设成开机启动,并生成基础配置。执行完之后/etc/multipath.conf里会有defaultsblacklistmultipaths等段落。这里有个坑:mpathconf生成的配置里user_friendly_names默认是yes,意味着设备名会是mpathampathb这种,而不是基于 WWID 的3600...长串。两种方式各有取舍,后面会专门讲。

2.4 启动服务并验证基础状态

# 启动并设置开机自启 systemctl enable multipathd systemctl start multipathd # 查看服务状态 systemctl status multipathd # 查看当前多路径设备 multipath -ll

如果multipath -ll输出为空,说明还没有设备被聚合。这时候先别怀疑配置,先确认底层是不是真的有多条路径。用multipath -v3可以看到详细的探测过程,它会告诉你哪些设备被扫描到、哪些被黑名单过滤、哪些因为 WWID 不合法被跳过。这个-v3的输出信息量很大,是排障的第一手资料。

3. multipath.conf 核心参数深度解析

3.1 defaults 段:全局行为的基调

defaults段决定了所有多路径设备的默认行为,是配置里最需要花心思的部分。下面这份是我在多个生产环境里验证过的配置,逐项说明为什么这么设:

defaults { user_friendly_names no polling_interval 10 path_selector "service-time 0" path_grouping_policy multibus failback immediate no_path_retry 5 rr_min_io_rq 1 max_sectors_kb 1024 dev_loss_tmo 60 fast_io_fail_tmo 5 find_multipaths yes }

user_friendly_names设成no是我强烈建议的。设成yes时,设备名mpatha是绑定到/etc/multipath/bindings文件的,这个文件一旦丢失或者换机器,名字就全乱了。而用 WWID 命名,设备名是3600508b400105e210000900000490000这种,虽然长,但它跟存储卷一一对应,任何机器上看到这个名字都知道是哪块盘。脚本里引用也更安全。

polling_intervalmultipathd检查路径状态的间隔,单位秒。默认 5 秒,我一般设 10 秒。设太小会增加系统开销,设太大故障发现不及时。10 秒是个平衡点,对大多数业务够用。

path_selector决定多条健康路径之间怎么分发 I/O。service-time 0是基于每条路径的预估服务时间动态选择,比老式的round-robin 0更智能。round-robin是无脑轮询,不管路径快慢,在链路性能不一致时会导致慢路径拖后腿。service-time会把 I/O 优先发给当前响应最快的路径,实测在混合链路环境下吞吐提升明显。

path_grouping_policy设成multibus表示所有路径放在一个组里,全部参与负载均衡。另一种常见值是failover,同一时刻只有一条路径 active,其余待命。multibus适合存储两个控制器都能同时服务的场景(比如 ALUA 的 active/active 模式),failover适合 active/passive 存储。选错了不会报错,但性能会差一大截。

failback控制路径恢复后是否切回。immediate表示路径一恢复就立刻切回,适合主备链路性能差异大的场景。如果两条链路对等,设成manual或一个较大的延迟值(如failback 30)可以避免频繁切换带来的抖动。

no_path_retry是路径全断后 I/O 的行为。设成数字表示重试多少次后失败,设成queue表示一直排队等待路径恢复。生产环境里我倾向设一个具体数字,比如 5,避免 I/O 无限挂起导致应用假死。但如果是数据库这种对 I/O 中断极度敏感的场景,queue配合合理的dev_loss_tmo更稳妥。

max_sectors_kb限制单次 I/O 的最大扇区数。默认值在不同内核版本上不一致,显式设成 1024 可以保证行为一致。设太大在某些存储上会触发超时,设太小又增加 I/O 次数。1024 是个保守稳妥的值。

dev_loss_tmofast_io_fail_tmo是配合使用的。fast_io_fail_tmo设成 5 秒,意味着链路出问题后 5 秒内快速失败,把 I/O 切到其他路径;dev_loss_tmo设成 60 秒,是设备彻底从系统移除前的等待时间。这两个值要保证fast_io_fail_tmo < dev_loss_tmo,否则快速失败没意义。

3.2 blacklist 段:把不该管的设备排除掉

黑名单非常重要,配不好会把本地盘也卷进多路径,导致系统盘无法启动。CentOS 7 上至少要排除本地 SATA/SAS 盘和虚拟设备:

blacklist { devnode "^sd[a-z]$" devnode "^hd[a-z]" devnode "^vd[a-z]" devnode "^cciss!c[0-9]d[0-9]*" wwid "3600508b400105e210000900000490000" }

devnode "^sd[a-z]$"这条会把所有单字母的 sd 设备排除,但多路径设备本身是/dev/dm-X,不受影响。注意这个正则只匹配sdasdz,如果服务器本地盘超过 26 块,需要调整正则。更稳妥的做法是用wwid精确排除,但前提是你知道本地盘的 WWID。

blacklist_exceptions段可以给黑名单开例外,比如某些设备虽然匹配了 devnode 规则,但你确实想让它走多路径:

blacklist_exceptions { wwid "3600d0230000000000e0d0a0000d3a1b2" }

3.3 multipaths 段:针对特定 LUN 的精细控制

全局配置管的是默认行为,但不同存储、不同业务对多路径的要求可能不一样。multipaths段允许你针对单个 WWID 做覆盖:

multipaths { multipath { wwid 3600d0230000000000e0d0a0000d3a1b2 alias data_lun01 path_grouping_policy multibus path_selector "service-time 0" failback immediate no_path_retry 10 } multipath { wwid 3600d0230000000000e0d0a0000d3a1b3 alias log_lun01 path_grouping_policy failover failback 30 } }

alias是给设备起个人性化名字,比mpatha更可控,比 WWID 更好记。设了 alias 之后,设备会出现在/dev/mapper/data_lun01。注意 alias 不能和已有设备名冲突,也不能包含斜杠。

这里有个经验:数据库数据盘和日志盘对 I/O 的要求不同,数据盘随机读写多,适合service-time选择器;日志盘顺序写多,round-robin反而可能更稳定。分 LUN 配置能把这些差异照顾到。

3.4 devices 段:存储厂商特定的参数

不同存储对 SCSI 命令的响应行为不一样,devices段可以针对厂商和产品型号设置参数:

devices { device { vendor "NETAPP" product "LUN" path_grouping_policy group_by_prio prio "alua" path_checker tur failback immediate no_path_retry 5 } device { vendor "HITACHI" product "DF.*" path_grouping_policy multibus path_checker readsector0 prio "alua" } }

path_checker决定用什么方式检测路径是否健康。tur(Test Unit Ready)是最通用的,发一个不产生实际 I/O 的命令探测;readsector0是读第一个扇区,对某些老存储更可靠但会产生实际读操作。选错了可能导致路径误判,比如某些存储对 TUR 响应慢,会被误认为路径故障。

prio是路径优先级算法。alua是 SCSI 标准里的非对称逻辑单元访问,存储会告诉主机哪些路径是优化的、哪些是非优化的。用alua配合group_by_prio策略,可以让 I/O 优先走优化路径,这是现代存储的最佳实践。

4. 实操验证与性能调优

4.1 配置生效与设备识别验证

改完配置后,标准操作流程是:

# 重新加载配置 systemctl reload multipathd # 或者完全重启 systemctl restart multipathd # 查看聚合结果 multipath -ll

multipath -ll的输出需要仔细读。一个健康的多路径设备长这样:

data_lun01 (3600d0230000000000e0d0a0000d3a1b2) dm-3 NETAPP,LUN size=500G features='1 queue_if_no_path' hwhandler='0' wp=rw `-+- policy='service-time 0' prio=50 status=active |- 2:0:0:1 sdb 8:16 active ready running |- 3:0:0:1 sdc 8:32 active ready running |- 2:0:1:1 sdd 8:48 active ready running `- 3:0:1:1 sde 8:64 active ready running

关键信息:dm-3是内核设备号,size=500G是容量,policy是选择器,prio=50是优先级,四条路径都是active ready running。如果某条路径显示failed faulty,说明那条链路有问题,需要查 HBA、光纤、交换机端口。

4.2 故障切换实测

配置完不测故障切换,等于没配。测试方法很简单,但要在业务低峰期做:

# 找到一条路径对应的 HBA 端口 ls -l /sys/block/sdb/device/scsi_device/ # 模拟链路故障(以 2:0:0:1 为例) echo 1 > /sys/block/sdb/device/delete

执行后立刻multipath -ll观察,应该看到sdb消失,其余三条路径仍然active,设备dm-3依然可用。同时开一个dd或者fio/dev/mapper/data_lun01上跑,I/O 不应该中断。

恢复测试用:

# 重新扫描 SCSI 总线 echo "- - -" > /sys/class/scsi_host/host2/scan

路径回来后,根据failback设置决定是否自动切回。immediate会立刻切回,manual需要手动执行multipathd reconfigure或者multipath -r

注意:echo 1 > /sys/block/sdb/device/delete这个操作在有些内核版本上会直接移除设备,有些只是标记。测试前确认业务能承受,最好在测试环境先演练一遍。

4.3 性能调优的关键参数

多路径的性能调优,核心是让 I/O 尽可能均匀且高效地分布在健康路径上。除了前面说的path_selector,还有几个参数值得调:

rr_min_io_rq是轮询模式下每条路径连续处理的 I/O 数。设成 1 表示每个 I/O 都换路径,设成 1000 表示一条路径处理 1000 个 I/O 再换。设太小会导致路径切换开销大,设太大又失去负载均衡意义。用service-time选择器时这个参数基本不起作用,但用round-robin时很关键。一般设 1 到 100 之间,SSD 存储可以设小一点,机械盘设大一点。

queue_if_no_path特性配合no_path_retry使用。当所有路径都断时,I/O 是排队还是直接失败。可以在features里显式指定:

features "1 queue_if_no_path"

数字 1 表示启用。这个特性在存储短暂抖动时能保住业务,但如果存储长时间不可用,I/O 会一直挂起,需要配合应用层的超时机制。

max_sectors_kb的调整需要结合存储的条带大小。如果存储条带是 256KB,把max_sectors_kb设成 256 的整数倍能让 I/O 对齐,减少读改写。这个值可以通过cat /sys/block/dm-3/queue/max_sectors_kb查看当前生效值。

4.4 用 fio 做基准测试

调优前后要有数据对比,fio是最常用的工具:

# 顺序读测试 fio --name=seqread --filename=/dev/mapper/data_lun01 \ --direct=1 --rw=read --bs=1M --size=10G \ --numjobs=4 --iodepth=32 --runtime=60 --group_reporting # 随机写测试 fio --name=randwrite --filename=/dev/mapper/data_lun01 \ --direct=1 --rw=randwrite --bs=4k --size=10G \ --numjobs=4 --iodepth=64 --runtime=60 --group_reporting

对比单路径和多路径的 IOPS、带宽、延迟。正常情况下,四条路径的聚合带宽应该接近单路径的四倍(受限于存储控制器和交换机背板)。如果提升不明显,检查是不是path_grouping_policy设成了failover,或者存储侧只允许一条路径 active。

提示:fio测试会破坏设备上的数据,务必在空 LUN 或者测试环境做。生产环境可以用--readonly参数只做读测试。

5. 常见问题排查与避坑经验

5.1 设备重复识别与黑名单失效

最常见的现象是multipath -ll里同一个 WWID 出现多次,或者本地盘被错误聚合。排查步骤:

  1. multipath -v3 2>&1 | grep -i "blacklist"看黑名单规则有没有匹配上。
  2. 检查blacklist里的正则是不是写错了,比如^sd[a-z]$匹配不了sdaa
  3. 确认find_multipaths的值。设成yes时,只有满足特定条件的设备才会被聚合,能减少误判;设成no时所有非黑名单设备都会被尝试聚合。

如果本地盘已经被聚合了,千万不要直接删/dev/mapper下的设备,可能导致系统盘不可用。正确做法是先把该 WWID 加入黑名单,然后multipathd reconfigure,再multipath -f刷新。

5.2 路径状态异常排查表

现象可能原因排查命令处理方式
路径显示 failed faulty光纤断、HBA 故障、交换机端口 downcat /sys/class/fc_host/host*/port_state检查物理链路,换端口
路径显示 active ghost存储 ALUA 非优化路径multipathd show paths format "%w %i %p %t"正常现象,I/O 会优先走优化路径
路径频繁 up/down链路抖动、SFP 光模块老化`dmesggrep -i "fc|scsi"`
所有路径消失存储控制器重启、交换机故障multipath -ll无输出检查存储和交换机状态
设备容量不对LUN 映射错误、WWID 冲突multipath -ll对比存储侧重新映射 LUN

5.3 服务启动顺序与依赖问题

CentOS 7 用 systemd 管理服务,multipathd的启动时机很关键。如果它启动太晚,可能在根文件系统挂载之后才运行,导致根分区无法使用多路径。检查/usr/lib/systemd/system/multipathd.service里的BeforeAfter设置,确保它在local-fs-pre.target之前启动。

另一个坑是multipathdiscsid的依赖关系。iSCSI 场景下,iscsid必须先启动并发现目标,multipathd才能看到设备。如果顺序反了,multipathd启动时没有设备可聚合,后面也不会自动补上。解决办法是在multipathd.service里加After=iscsid.service,或者手动systemctl restart multipathd

5.4 配置文件语法错误的隐蔽性

multipath.conf的语法检查不算严格,有些错误不会导致服务启动失败,但配置不生效。比如:

  • 段落名拼错:default写成defaults才对。
  • 参数值没加引号:path_selector service-time 0会被解析成两个 token,必须写成path_selector "service-time 0"
  • 大括号不匹配:少一个}会导致后面所有配置被忽略。

改完配置后,用multipathd -k"show config"可以查看实际生效的配置,对比你写的文件,能发现哪些没被加载。这个命令比重启服务再猜要高效得多。

5.5 udev 规则与设备权限

多路径设备默认属主是root:disk,权限brw-rw----。如果业务以非 root 用户运行,需要调整 udev 规则:

# /etc/udev/rules.d/99-multipath-permissions.rules KERNEL=="dm-*", SUBSYSTEM=="block", PROGRAM="/sbin/multipath -c /dev/$name", RESULT=="*", OWNER="oracle", GROUP="oinstall", MODE="0660"

改完udevadm control --reload-rules && udevadm trigger生效。注意规则里的PROGRAM调用multipath -c判断是不是多路径设备,避免影响其他 dm 设备。

6. 生产环境落地建议

6.1 配置版本化管理

multipath.conf是核心配置文件,必须纳入版本管理。我习惯在文件头部加注释记录变更:

# multipath.conf # 2024-01-15 初始配置,适配 NETAPP E系列 # 2024-03-02 调整 no_path_retry 从 queue 改为 5,解决存储维护时 I/O 挂起 # 2024-06-10 新增 log_lun01 的 failover 配置

配合 Git 或者内部配置管理平台,每次变更都有记录,出问题能快速回滚。

6.2 监控与告警

multipathd本身不提供监控接口,但可以通过multipathd show paths的输出做监控。关键指标:

  • 路径状态:任何一条路径非active ready就告警。
  • 路径数量:少于预期数量告警。
  • 设备状态:multipath -ll里设备不是rw状态告警。

可以用 Zabbix 或者 Prometheus 的自定义脚本采集,也可以写个简单的 shell 脚本定时检查:

#!/bin/bash # check_multipath.sh failed=$(multipathd show paths | grep -v "active ready" | grep -c "^") if [ "$failed" -gt 0 ]; then echo "WARNING: $failed paths not ready" multipathd show paths | grep -v "active ready" exit 1 fi exit 0

6.3 变更窗口与回滚预案

多路径配置变更涉及存储链路,必须在变更窗口做。回滚预案要提前准备好:

  1. 备份当前multipath.conf
  2. 记录当前multipath -ll输出。
  3. 如果变更后业务异常,立即恢复配置文件并systemctl restart multipathd
  4. 如果设备名变了导致挂载失败,用 WWID 重新挂载。

最稳妥的做法是在测试环境先验证一遍完整流程,包括故障切换和恢复。

6.4 与集群软件的配合

如果服务器上跑的是 Oracle RAC、Pacemaker 这类集群软件,多路径设备的命名必须稳定。用 WWID 命名或者固定的 alias 是关键。集群软件通常有自己的存储检查机制,要确保它检查的是/dev/mapper/下的设备,而不是底层的/dev/sdX

另外,集群软件可能会自己管理设备挂载和卸载,要确认它的操作不会和多路径的failback冲突。比如集群在路径切换时执行了multipath -f,可能导致设备被移除,影响其他节点。

6.5 内核参数配合调优

多路径的性能还受一些内核参数影响:

# /etc/sysctl.d/99-multipath.conf # SCSI 层命令超时,默认 30 秒,可适当调大 kernel.sysrq = 0 # 提高 SCSI 设备队列深度 # 通过 /sys/block/dm-X/queue/nr_requests 调整

nr_requests是块设备层的请求队列深度,默认 128。高并发场景可以调到 256 或 512,但要注意内存占用。调整方法:

echo 256 > /sys/block/dm-3/queue/nr_requests

这个值重启后会恢复,需要写进 udev 规则或者 systemd 服务里持久化。

6.6 存储侧配合的注意事项

多路径不是主机单方面的事,存储侧的配置同样关键:

  • ALUA 配置:确认存储的 ALUA 状态是 active/active 还是 active/passive,主机侧的path_grouping_policy要匹配。
  • LUN masking:确认 LUN 只映射给需要的服务器,避免多台主机同时看到同一 LUN 导致数据损坏。
  • 控制器固件:保持存储控制器固件和 HBA 固件版本兼容,厂商兼容性列表要查。
  • 交换机 zoning:FC 交换机的 zoning 配置要确保每条路径独立,避免单点故障。

我在实际项目中遇到过存储侧 ALUA 配置错误,导致主机侧所有路径都被标记为优化路径,group_by_prio策略失效,I/O 全部涌向一个控制器。后来在存储侧修正 ALUA 状态,主机侧multipath -llprio值才正常区分。这个案例说明多路径调优必须主机和存储两边一起看,单看一边容易误判。

最后分享一个我常用的快速检查脚本,登录服务器后跑一遍,基本能判断多路径状态是否健康:

#!/bin/bash echo "=== multipathd 服务状态 ===" systemctl is-active multipathd echo "=== 多路径设备列表 ===" multipath -ll echo "=== 路径状态统计 ===" multipathd show paths | awk '{print $NF}' | sort | uniq -c echo "=== 黑名单检查 ===" multipathd show blacklist echo "=== 最近内核 SCSI 错误 ===" dmesg | grep -i "scsi\|fc" | tail -20

这个脚本输出信息量足够,日常巡检和故障初判都能用。多路径这东西,配好之后平时不用管,但一旦出问题就是存储链路级别的事故,所以前期的配置严谨度和监控覆盖度,直接决定了后面是省心还是救火。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询