LVM Thin Provisioning and Thin Snapshots in Practice - 夜莺博客

LVM Thin Provisioning and Thin Snapshots in Practice

Thin provisioning decouples the size a volume claims from the space it consumes: blocks are allocated on write. That makes snapshots nearly free and overprovisioning cheap, but it also means the pool is a shared resource that can fill up underneath every volume that uses it. This guide covers building the pool, using thin snapshots correctly, and monitoring the two numbers that cause outages when ignored.

Why Thin Provisioning Changes Capacity Planning

A classic logical volume reserves its full size the moment you create it. Like the parity penalty discussed in RAID levels and the parity write hole, that is a reserve you pay for up front whether or not you write the data. Thin provisioning inverts the model: the volume advertises a virtual size, and the pool hands out a physical chunk only when a block is first written. A 1 TB thin volume on a 400 GB pool will work fine — right up until the pool runs out, at which point every volume in it stops, not just the one that filled it.

That is the whole trade. You gain space efficiency, instant snapshot creation and cheap clones; you take on the obligation to monitor pool consumption continuously and to decide, in advance, what happens when the pool fills.

Create the Pool and Thin Volumes

vgcreate vg0 /dev/nvme0n1
lvcreate --type thin-pool -L 400G -n thinpool vg0
lvcreate -V 1T --thin-pool vg0/thinpool -n vm-disk0
lvs -o name,size,data_percent,metadata_percent vg0

A thin pool is two hidden volumes behind the scenes: _tdata holds the blocks and _tmeta holds the mapping metadata maintained by the dm_thin_pool kernel module. A virtual size of 1 TB on a 400 GB pool is normal - and exactly why you must watch Data% and Meta%.

Two sizing decisions are worth making deliberately on the first run, because shrinking either one later is painful:

lvcreate --type thin-pool -L 400G --poolmetadatasize 4G \
  --chunksize 128k -n thinpool vg0
  • Metadata size — the default is derived from pool size and chunk size, and it is frequently too small for pools carrying millions of small blocks. Budget roughly 1 GB of metadata per 100 TB of chunk space, and add headroom if the pool will hold many snapshots. Running out of metadata is worse than running out of data space: it cannot be autoextended as simply, and it makes the pool unactivable.
  • Chunk size — 64 KB to 1 GB, defaulting to 64 KB. Larger chunks mean less metadata and better sequential throughput; smaller chunks mean less wasted space when a volume only touches a few blocks. 128 KB to 256 KB is a reasonable middle for VM disks.

Then put a filesystem on the thin volume and mount it:

mkfs.xfs /dev/vg0/vm-disk0
mkdir -p /srv/vm-disk0
mount /dev/vg0/vm-disk0 /srv/vm-disk0

Nothing is allocated to the pool until you write. Check that with lvs -o name,size,data_percent after the mkfs — you will see a small percentage appear, because the filesystem wrote its superblocks and journals, and nothing more.

Thin Snapshots Done Right

! correct: no size argument - this creates a thin snapshot
lvcreate --snapshot -n vm-disk0-snap1 vg0/vm-disk0
! snapshot of a snapshot is fine
lvcreate --snapshot -n vm-disk0-snap2 vg0/vm-disk0-snap1
! remount as a writable clone
lvconvert --thinpool vg0/thinpool

The one mistake to avoid is passing -L/--size: with a size, LVM creates a classic copy-on-write snapshot with a fixed chunk store that becomes a performance problem as it fills. Thin snapshots share unchanged blocks, so chains of them do not degrade the way stacked COW snapshots do - but they still consume pool space as origin and snapshot diverge.

Snapshots are also far more useful than most people realise, because they can be mounted and written to as independent volumes:

lvchange -ay -Ky vg0/vm-disk0-snap1
mkdir -p /mnt/snap1
mount -o ro /dev/vg0/vm-disk0-snap1 /mnt/snap1
! promote a snapshot into a full independent volume
lvconvert --setactivationskip n vg0/vm-disk0-snap1

The -K flag tells LVM to activate a snapshot even though it is normally skipped at boot — important to remember after a reboot, when a snapshot may not be present until you activate it explicitly.

To roll a volume back, merge the snapshot into the origin. The origin must be unmounted, and LVM performs the merge at the next activation:

umount /srv/vm-disk0
lvconvert --merge vg0/vm-disk0-snap1
lvchange -ay vg0/vm-disk0
mount /dev/vg0/vm-disk0 /srv/vm-disk0

A merge is a destructive, one-shot operation on the snapshot — the snapshot disappears when it completes. Take a fresh snapshot immediately after a rollback so you are covered again.

Monitor What Actually Matters

Two numbers cause every thin-pool outage: data percentage and metadata percentage. Watch both, at a sampling interval short enough to catch a sudden fill.

lvs -a -o name,size,data_percent,metadata_percent,lv_health_status vg0
lvs --reportformat json vg0 > /var/lib/prometheus/node-exporter/lvm_thin.json
dmsetup status vg0-thinpool

The JSON report format exists so exporters can scrape it without parsing fixed-width text; wiring it into node-exporter or a small script that alerts at 80 percent data and 70 percent metadata will save you an incident. Alert thresholds should be well below the autoextend trigger so a human hears about it before dmeventd has to act.

Keep the Pool From Filling

lvextend --use-policies vg0/thinpool
lvextend -L+100G vg0/thinpool
systemctl status lvm2-monitor

dmeventd's thin plugin watches the pool and can autoextend it with lvextend --use-policies, provided there is free space in the volume group - so keep headroom in the VG, not just the pool. Decide the pool-full behaviour deliberately: the default suspends the pool, which stops every volume in it, including the database that depends on it.

The behaviour is driven by two settings in /etc/lvm/lvm.conf:

thin_pool_autoextend_threshold = 70
thin_pool_autoextend_percent = 20

With those values, dmeventd extends the pool by 20 percent each time data usage crosses 70 percent. The alternative is activation { thin_pool_autoextend_threshold = 100 }, which disables autoextend entirely and lets the pool fill — a deliberate choice for environments where an unexpected extension would exhaust the VG is worse than a controlled outage. Whichever you choose, make sure the volume group has free extents, otherwise autoextend silently fails and you are back to a suspended pool.

Reclaiming Space and Discards

Deleting a file inside a thin volume does not necessarily return blocks to the pool. Whether it does depends on the filesystem and the discard settings:

! mount-time discard
mount -o discard /dev/vg0/vm-disk0 /srv/vm-disk0
! or periodic trim, which is usually the better choice
fstrim -av
lvs -o name,data_percent vg0

For ext4 and XFS on modern LVM, also check the issue_discards setting in lvm.conf — with it disabled, LVM will not pass discards through at the device-mapper layer even when the filesystem issues them.

Metadata Recovery

lvs -a -o+lv_health_status vg0
thin_check /dev/vg0/thinpool_tmeta
thin_repair -i bad_tmeta -o good_tmeta

If the kernel could not cleanly close the pool, it flags needs_check and the next activation performs a check. Learn thin_check/thin_repair now rather than during an incident - and keep a vgcfgbackup copy of the VG metadata outside the machine. Fragmentation is the other long-term cost: on-demand allocation across a busy pool degrades throughput compared with a fully provisioned LV, so thick LVs remain a reasonable choice for I/O-sensitive workloads such as iSCSI targets. Networking-side storage transports are covered in systemd-networkd VLAN/bond/bridge configuration, and virtualised guests that lean on these pools in Proxmox VE Linux bridge and VLAN setup.

For the offline-tooling side of that recovery, two commands matter more than any other:

dmsetup remove vg0-thinpool
thin_restore -i good_metadata.bin -o /dev/vg0/thinpool_tmeta
vgcfgbackup -f /root/vg0-backup-$(date +%F).cfg vg0
vgcfgrestore -f /root/vg0-backup-2026-01-01.cfg vg0

You cannot repair metadata on an active pool: deactivate every thin volume and the pool first, then run the check offline. Keep the vgcfgbackup copies on a different machine, because metadata loss on the machine that also held the only backup is the scenario that turns a bad afternoon into a restore from off-site.

Snapshots as a Backup Window

The least glamorous but most valuable use of thin snapshots is shrinking a backup window. Backing up a live, multi-terabyte virtual disk over the network takes hours and produces a fuzzy point in time. Instead: snapshot, back up from the snapshot, then delete it.

lvcreate --snapshot -n nightly-$(date +%F) vg0/vm-disk0
lvchange -ay -Ky vg0/nightly-2026-01-01
! point the backup job at /dev/vg0/nightly-2026-01-01
lvremove vg0/nightly-2026-01-01

The snapshot is consistent at the instant it is taken, so the backup reflects one point in time even though the origin kept running. The cost is that the origin now writes into the pool as it diverges, so a long backup of a busy volume consumes real pool space — schedule it and watch Data% while it runs.

Thin or Thick: Deciding Per Workload

  • Snapshot-heavy workloads — VM images, container build caches, developer environments. Thin wins outright; the snapshots are the point.
  • Databases with unpredictable growth — thin is fine, but only with generous volume-group headroom and alerting that fires long before the autoextend threshold.
  • Storage exported to other hosts — thick LVs give predictable latency and no surprise suspension of a shared pool. See iSCSI target configuration with targetcli.
  • Anything where the virtual size is a promise to a customer — a thin volume cannot be shrunk, and the pool is the only thing standing behind the promise.

Converting an existing classic LV to thin is possible when a host was built before thin provisioning became standard:

lvconvert --thinpool vg0/thinpool vg0/legacy-lv
lvextend -L+200G vg0/vm-disk0
xfs_growfs /srv/vm-disk0

A thin volume can be extended while mounted as long as the pool can satisfy the request, after which the filesystem is grown with xfs_growfs or resize2fs. Shrinking is not supported — treat the virtual size as a decision you get to make once.

Performance Notes

  • First-write penalty — a block that has never been written must be allocated and its mapping recorded before the write completes. Freshly provisioned thin volumes benchmark slower until the working set has been touched once.
  • Fragmentation — allocation on demand scatters chunks over time. For steady high-throughput workloads, a thick LV on a dedicated physical range is predictable where a busy thin pool is not.
  • Snapshot chains — deep chains are cheap in space but add indirection on reads. Two or three generations is comfortable; dozens is not.
  • Zeroing — lvcreate -Z y zeroes the first blocks of a new volume. Thin volumes arrive zeroed by nature, so this is mostly a thick-volume concern.

原文链接:https://man7.org/linux/man-pages/man7/lvmthin.7.html