LVM 快照既不是拷贝,也不是 reflink:它是一个挂在源逻辑卷上的、大小固定的写时复制异常存储。lvcreate -s -L 5G -n snap vg/data 从卷组里划走 5 GiB,之后 device-mapper 的 snapshot 目标会在某个源 chunk 第一次被写时,把它的原始内容记录下来。无论源卷多大,创建都是瞬时的,因为创建时什么都没复制。

这个大小就是你全部的安全余量,也正是最常被写错的参数。按“一周内没什么写入”配的存储,会被一次数据库 checkpoint 或一次 rsync 在一小时内吃光;而它填满时快照不会降级,而是直接失效并开始返回 I/O 错误。恢复点恰好在你最需要它的那一刻消失,所以存储的剩余空间该进监控面板,而不是躺在 runbook 里。

异常存储,不是副本

一个经典的 LVM 快照用到两个 device-mapper 目标:源卷被重新映射为 snapshot-origin,另有一个新的 snapshot 设备把它与 COW 设备组合起来。读未改动的 chunk 直接落到源卷;某个 chunk 第一次被写时,旧 chunk 被复制进 COW 设备,然后新数据才写下去。所以消耗量跟“发生过改动的不同 chunk 数”成正比,而不是跟写入次数成正比:fixture 往 16 个热 chunk 写了一百万次,只消耗 15 个异常,约 60 KiB。

用 lvs -a -o lv_name,lv_attr,origin,data_percent,lv_size 观察它。经典快照的 lv_attr 是 swi-a-s---:s 表示快照、w 表示可写,而状态位在存储耗尽时会变成 I。data_percent 是存储的填充度,这才是该告警的数字,阈值取 70% 或 80%;100% 不是警告,是讣告。--chunksize 决定异常存储的粒度:粒度越大,块映射表的元数据越省,但每一次改动要拷贝的旧数据也越多。快照还有效时可以用 lvextend 扩容 COW 设备;lvchange --monitor y 则让 dmeventd 自动做这件事。

耗尽即失效

内核文档说得很直白:COW 设备往往比源卷小,一旦填满,快照就变得无用并被禁用,开始返回错误。LVM 给出的容量经验是按预期写入量规划——常常取源卷的 20%——并在填满之前扩容。另外,存储里有一小块要用来存放 COW 块映射表,所以可用于数据的容量略小于 -L 的数值。

影响范围很窄,但时机很残忍:源卷照常运行,所以在读取该快照的备份任务失败之前,或者在你要用的那次回滚已经不可用之前,看不出任何异常。它没有中间状态:到了 100%,正确的心理模型是这份快照从未存在过。

合并回滚,以及 thin 如何改变失败形态

lvconvert --merge vg/snap 把快照中改动过的 chunk 合并回源卷,合并在后台进行,期间源卷仍然可用——对尚未合并的 chunk 的写入会被推迟。约束在源卷一侧:建立合并时它必须处于非活动状态,所以要么先卸载,要么先安排合并、之后再激活源卷。合并只对持久化快照有效,临时快照走不了这条路;合并会消耗掉这份快照,所以需要的东西先拷出来。

thin 快照改变的是失败形态,而不是消除失败。当源是 thin LV 且不给大小时,创建出来的就是 thin 快照;它共享 thin 池里的块,而不拥有自己的存储,所以它自身的分岔无法让它失效。此时共享资源变成了池:池一旦耗尽,坏掉的不是一份快照,而是池里所有 thin 卷,而 LVM 明确警告池可能因此损坏、且难以甚至无法修复。thin_pool_autoextend_threshold 与 dmeventd 的存在,正是因为池耗尽是一次池级事故。

坏掉的样子

最经典的是“备份悄悄不再是备份”。任务挂载快照开始拷贝,拷贝耗时超过了存储能覆盖的时长,存储在某刻到达 100%;快照随即失效,拷贝失败——更糟的情况是,监控只看任务的退出码,而任务读的早就是一个过期的挂载点。所以要盯每一个快照 LV 的 data_percent,70% 就告警,并且按保留窗口内最忙的那一小时来定容量,而不是按平均值。

第二种是“要用的时候合并不了”。lvconvert --merge 要求源卷处于关闭状态,而团队往往是在事故当中才发现这一点。合并开始后由 snapshot-merge 目标接管源卷,dmsetup status 里的已分配扇区数会持续下降,降到只剩元数据就表示合并完成。先在一个一次性卷上演练合并,另留一份不依赖快照的真实备份,并记住:存储已满的快照根本无法合并。

快速验证

在信任这份快照之前,先看存储的填充度:

lvs -a -o lv_name,vg_name,lv_attr,origin,data_percent,lv_size
lvs -a -o lv_name,data_percent,metadata_percent vg/thinpool
dmsetup status vg-snap
lvextend -L +2G vg/snap

data_percent 就是 COW 存储的填充度,健康的快照应当远低于 100;lv_attr 里出现状态位 I 说明快照已经失效。对 thin 快照而言,该看的是池上的 data_percent 与 metadata_percent;dmsetup status 会给出已分配扇区与总扇区之比,可以据此实时观察一次合并把扇区数排空的过程。

来源

  • lvcreate(8),说明 -s/--snapshot、COW 与 thin 快照的区别以及容量建议,已核验 2026-09-16。
  • lvs(8),定义 lv_attr 状态位,含无效快照,已核验 2026-09-16。
  • Device-mapper snapshot 支持,异常存储、失效语义与 lvconvert --merge 行为,已核验 2026-09-16。
  • lvmthin(7),thin 快照、池耗尽与自动扩容,已核验 2026-09-16。