共享块存储双机切换:Device-Mapper映射残留清理实战

发布时间:2026/10/30 5:12:00
共享块存储双机切换:Device-Mapper映射残留清理实战 简介面向 Linux 运维与系统管理人员的存储排错资料聚焦同一存储设备挂载到两台服务器后一台正常、另一台无法挂载或提示“存储正忙”的典型故障帮助读者理解多机共享存储时的设备映射冲突与占用问题。包内仅含 1 个 docx 文档约 11KB篇幅精简便于快速查阅与归档适合作为日常运维排障的参考笔记。内容围绕 Device-Mapper 框架与 dmsetup 命令展开涉及存储设备映射关系的查看与清理、remove_all 的适用场景以及快照、克隆、镜像等数据保护能力的介绍并给出从冲突成因到处理思路的整理。已有 1650 人学习下载可作为理解 Linux 存储管理机制、补充多服务器挂载排错经验的轻量资料。1. 存储正忙不是玄学双机挂同一块盘的僵局与破局点一台服务器宕机或被下线另一台明明看到设备节点还在mount却报device is busy或者干脆卡在挂载阶段不返回——这个场景在共享块存储环境里非常经典。根因往往不是文件系统坏了而是 Device-Mapper 的映射关系还挂在这台机器的内核里没退干净设备节点名可能已经变了/dev/mapper下的条目还在I/O 路径还指向一块已经不属于自己的盘。这篇笔记拆的是一个常被当成“重启治百病”的问题实际操作只需要两步看清映射再清映射。适合管共享存储、做双机切换、碰过dmsetup但不敢乱敲的人。2. Device-Mapper 的映射残留为什么重启能好、不重启怎么好2.1 先厘清“同一块存储挂两台”到底是什么状态先把一个容易混淆的点摆平Linux 里“同一块存储挂到两台服务器”本身不违法违法的是两台同时读写同一个文件系统。块设备层面的多路径、集群文件系统、只读挂载都是设计允许的用法。真正出事的是那种“我以为是 A 机在用B 机其实一直留着映射”的半吊子状态。典型的时间线是这样的存储通过光纤或 iSCSI 映射给两台机器A 机先做了 LVM 或直接mountB 机也扫到了同一块盘。此时 B 机上会多出/dev/mapper下的条目、/dev/dm-N设备节点甚至pvs能看到 PV 的元数据。等到 A 机故障、需要把业务切到 B 机时B 机去mount内核发现这个块设备的 holder 链没断或者 multipath 的队列还压着未完成的 I/O于是返回正忙。这里有个认知偏差要纠正很多人以为“我没敲过mount就不算挂载”。Device-Mapper 的映射在dmsetup create、multipath 自动发现、LVM 激活lvchange -ay时就已经建立了跟文件系统挂载是两回事。映射层在设备就是“被占用”的。判断当前处于哪种状态先看三样东西设备节点、映射表、谁在持有设备。# 1. 看块设备拓扑确认盘是不是被 dm 接管 lsblk -o NAME,MAJ:MIN,SIZE,TYPE,MOUNTPOINT # 2. 看 device-mapper 里有哪些映射以及它们的状态 dmsetup ls --tree dmsetup info -c # 3. 看谁在持有这个块设备关键holders 目录 ls -l /sys/class/block/dm-*/holders/ 2/dev/null # 4. 反查映射被哪个进程或挂载点占着 fuser -m /dev/mapper/vg-lv 2/dev/null第一行lsblk里如果看到某个mpatha、vg-lv的TYPE是dm或lvm说明映射存在。dmsetup ls --tree的树状输出能看清上层是 multipath 还是 LVM底层是不是(8,16)这类真实盘符。holders目录最有诊断价值——里面如果有dm-3这种子设备说明有上层映射压着你直接删底层会失败或留下脏状态。参数上要注意dmsetup info -c的列Name、Maj、Min、Open。Open计数大于 0代表这个映射有打开者可能是挂载、可能是 LVM、也可能是某个还在跑的进程。这个数字是判断“能不能安全删”的第一道闸门。2.2 dmsetup remove_all 到底删了什么、不删什么dmsetup remove_all执行的动作很干脆遍历当前所有 device-mapper 设备对每一个调用remove。语义等价于对所有dm-N循环跑dmsetup remove。它能清掉的是映射表项——multipath 的 mpath 设备、LVM 的 linear/striped 映射、crypt 设备、thin 的顶层映射都会被摘掉。它不碰的东西同样要清楚物理盘上的分区表纹丝不动文件系统超级块不动LVM 的元数据还在 PV 头部multipath 的配置文件/etc/multipath.conf不改/etc/fstab也不动。所以remove_all是“拆管道”不是“拆水管”数据本身不会因为这个命令丢——前提是你没在映射上跑着业务。这也解释了为什么重启能好重启过程中内核态 dm 表随内核一起销毁udev 重新扫描映射被重建或不再建立残留自然消失。但重启的代价是整机业务中断而且如果 multipath 配置了自动发现重启后映射又回来了问题可能复发。这就是为什么要学“不重启怎么好”。还有一处容易翻车remove_all对正在使用中的映射会返回device-mapper: remove ioctl on xxx failed: Device or resource busy并且继续尝试下一个。也就是说它不保证原子性可能出现“删了一半”的中间态——部分映射没了部分还在。这时候盲目重跑或者直接重启故障现场就丢了。所以标准动作不是上来就remove_all而是先做一次“只读勘查”把映射树、打开计数、挂载点、multipath 状态全记下来再决定是整体清还是定点清。我给自己的规矩是任何一次remove_all之前dmsetup table的完整输出必须落盘留档# 留档把当前所有映射的定义存下来出问题能对照 mkdir -p /tmp/dm-backup cd /tmp/dm-backup dmsetup table dm-table-$(date %F-%H%M).txt dmsetup ls --tree dm-tree-$(date %F-%H%M).txt multipath -ll mpath-$(date %F-%H%M).txt 2/dev/null cp -a /etc/multipath.conf /tmp/dm-backup/ 2/dev/nulldmsetup table输出的是每个映射的 target 类型、起止扇区、底层设备号这是重建映射的唯一依据。如果你只有dmsetup ls的名单删掉之后想恢复就得靠 LVM 元数据或 multipath 重扫虽然通常能恢复但多一层不确定性。归档这一步花十秒省的是后面半小时的猜测。2.3 完整处理流程从勘查到清映射再到重挂下面这条流程是我在双机切换场景里反复用过的顺序按它走基本不会把盘搞成悬空状态。前提是已确认业务侧可以停A 机不再写这块盘。# 步骤一确认没有进程和挂载点占着目标设备 mount | grep -E mapper|mpath fuser -vm /dev/mapper/vg-lv # 有任何输出先解决占用别往下走 # 步骤二如果挂了文件系统先正常卸载 umount /data 2/dev/null || umount -l /data # -l 是懒卸载仅在前一步失败且确认无写入时使用 # 步骤三停掉可能自动重建映射的服务避免边删边建 systemctl stop multipathd 2/dev/null # LVM 场景下同时关闭自动激活 # 编辑 /etc/lvm/lvm.conf 中 activation/auto_activation_volume_list 或临时 vgchange -an vg # 步骤四清空 device-mapper 映射 dmsetup remove_all # 若有残留逐个处理并看报错 dmsetup ls # 步骤五重新发现并挂载 systemctl start multipathd 2/dev/null multipath -r # 重载 multipath 映射 vgscan vgchange -ay vg mount /dev/mapper/vg-lv /data逐条说关键点。步骤一里fuser -vm比lsof更贴近块设备层能看到持有设备的内核线程mount | grep要连mpath一起过滤因为挂载点可能写的是/dev/mapper/mpatha1而不是 LVM 路径。步骤二的umount -l是后悔药也是陷阱它只是把挂载点从命名空间摘掉底层 I/O 可能还在跑只有在确认无人写入时才用。步骤三是全流程里最容易被跳过、也最容易导致“删了又回来”的一步。multipathd 在跑的时候可能在你remove_all之后几百毫秒内重新创建 mpath 设备LVM 的 autoactivation 同理。所以先停服务、先vgchange -an再清映射顺序反了整个流程就白做。步骤五的multipath -r是重载而非重启比重启 multipathd 温和vgscan要在 multipath 重载之后跑否则扫到的还是旧路径。如果步骤四里remove_all报 busy 且有明确设备名说明那个映射还有 holder。此时不要硬删先用dmsetup info -c name看Open计数再回步骤一查占用实在查不到就用dmsetup udevcomplete_all清 udev 事件队列再重试。整个过程里最忌讳的是“报错了就重启”因为重启会掩盖真实原因下次换台机器照样复发。3. 双机争用的避坑清单五条血泪经验与排查顺序3.1 现象remove_all 报 busy但 mount 里什么都没有原因通常不在文件系统层而在 holder 链或者 udev 事件没处理完。设备被某个 LVM 映射引用、被 multipath 的队列持有或者 udev 的cookie还挂着都会让 remove 返回 busy。解决顺序先dmsetup info -c name看Open计数再ls /sys/class/block/dm-N/holders/看子设备然后dmsetup udevcomplete_all清事件队列最后重试dmsetup remove name。不要用remove_all -f之类的强制手段也不要用dmsetup wipe_table绕过——那是清 I/O 表而不是删设备会把状态搞得更乱。3.2 现象删完映射重挂时报“找不到卷组”原因多半是vgchange -an之后没重新vgscan或者 multipath 映射还没重建就去激活 LVM。LVM 的 PV 定位依赖底层路径路径没回来元数据自然读不到。解决严格按multipath -r→vgscan→vgchange -ay的顺序走。如果vgscan报Duplicate VG name说明两台机器同时看到了同一个 VG 且都被激活过这属于双机争用的本质问题靠dmsetup治标不治本得回到集群文件系统或单活策略上。3.3 现象A 机重启后映射自动回来B 机又被挡原因是有自动发现机制在跑——multipath 的find_multipaths、LVM 的 autoactivation、systemd的lvm2-activation服务任何一个都可能在你操作完把映射建回去。解决切换期间把这些自动行为临时关掉别指望它们“应该不会”。systemctl stop multipathd、vgchange -an必要时在lvm.conf里用auto_activation_volume_list白名单限制。做完切换再恢复。这条是我吃过最多次亏的命令执行完看着干净过一分钟再看又乱了。3.4 现象umount 成功但 remove 时提示资源忙原因是有进程的工作目录或打开的文件句柄还落在挂载点下umount只是摘了挂载点进程没退。也可能是有内核线程在做回写。解决fuser -vm mountpoint找出进程确认可杀再杀sync之后再umount如果报target is busy先查lsof D mountpoint。实在紧急才用umount -l并且必须紧接着dmsetup remove中间不要停留否则懒卸载的延迟会让映射处于半挂状态。3.5 现象清完映射后盘符顺序变了脚本挂错盘原因/dev/sdX这类命名不稳定remove_all之后重新扫描设备字母可能整体后移写死/dev/sdb1的脚本直接挂到别的盘上。解决一律用/dev/disk/by-id/、/dev/disk/by-uuid/或/dev/mapper/下的稳定路径别在脚本里写sdX。这条跟dmsetup没直接关系但它是双机切换里最容易造成二次事故的隐形坑。切完盘先lsblk -f确认挂的是对的那块再执行mount。4. 把切换做成可回滚的脚本验证与加固的六个细节前面给的是手工流程真正在双机上反复切得把它固化成带校验的脚本否则每次靠人记顺序迟早出错。下面这段是我平时用的骨架核心思路是每一步都“先验证再执行”任何一步不满足就退出不做半截操作。#!/usr/bin/env bash set -euo pipefail VGvg_data; LVlv_data; MNT/data LOG/var/log/dm-switch-$(date %F-%H%M).log exec (tee -a $LOG) 21 # 前置校验挂载点必须干净否则拒绝继续 if mountpoint -q $MNT; then echo 挂载点仍被占用终止; exit 1 fi # 留档删之前先存 dmsetup table /tmp/dm-table-$(date %s).txt dmsetup ls --tree # 停自动重建防止边删边建 systemctl stop multipathd 2/dev/null || true vgchange -an $VG 2/dev/null || true # 清映射失败时输出诊断而不是直接退出 if ! dmsetup remove_all; then dmsetup info -c ls -l /sys/class/block/dm-*/holders/ 2/dev/null || true dmsetup udevcomplete_all || true dmsetup remove_all || { echo 映射清理失败保留现场; exit 2; } fi # 重新发现并校验 systemctl start multipathd 2/dev/null || true multipath -r vgscan vgchange -ay $VG lsblk -f /dev/mapper/${VG}-${LV} # 确认文件系统类型与 UUID 对得上 mount /dev/mapper/${VG}-${LV} $MNT findmnt $MNT脚本里值得展开的有几处。set -euo pipefail让任何未被处理的失败立即中断避免脚本带着错误继续往下挂载。exec (tee -a $LOG)把全流程输出同时落日志事后能复盘——切换出问题的时候日志比记忆可靠。mountpoint -q做前置闸门比在脚本里mount | grep更稳因为grep会误匹配相近路径。vgchange -an前的|| true是有意的卷组本来就没激活时它返回非零不应该因此中断流程但失败又不该被完全忽略所以配合日志看。dmsetup remove_all的失败分支是全脚本信息量最大的部分——它不直接退出而是先把info -c、holders 目录、udev 队列全打出来再重试一次还不行才保留现场退出。这个设计来自一个教训早期版本我一失败就exit结果日志里只有一个“busy”完全不知道是谁占着。最后的校验环节有两层。lsblk -f看文件系统类型、UUID、挂载状态确认挂的是预期的那块盘而不是同名的另一块findmnt确认最终挂载点生效。这两步别省尤其在多路径环境下lsblk的NAME列会显示mpatha而不是sdX正好用来复核路径没走错。再补两个加固细节。其一脚本不要在 A 机还活着的时候在 B 机上跑——remove_all只管本机内核管不了 A 机的写入双写风险它解决不了。真正的判断依据是存储侧或仲裁侧确认 A 机已下线。其二切换完成后把multipathd和 LVM 自动激活恢复回去否则下次重启机器时映射不会自动建反而变成新的故障。我给自己的习惯是脚本结尾加一句恢复服务状态的提示人工确认后再执行不自动恢复——宁可多一步也不让自动化替我做主。从那以后我每次碰共享块存储的切换都强制先跑一遍只读勘查、把dmsetup table和multipath -ll落盘再谈动手这个习惯救过我不止一次因为真正让人翻车的从来不是remove_all这条命令本身而是删之前没看清盘现在归谁。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询