openSUSE默认使用btrfs作为根文件系统,并通过Snapper在每次zypper操作前后自动创建快照。这套机制让系统出问题时可以一键回滚,安全性极高,但代价是磁盘空间会被不断累积的快照悄悄吃掉。如果不主动配置清理策略,用上几个月后很可能遇到根分区报警、系统卡顿甚至无法更新的情况。本文将从Snapper的清理原理讲起,逐步介绍自动清理的配置方法与实用调优技巧。

Snapper快照为什么会越积越多
要理解清理机制,先要明白快照是怎么产生的。Snapper维护着多个快照类型:编号快照(NUMBER)、时间线快照(TIMELINE)以及成对的pre/post快照。当配置了timeline功能后,Snapper会按固定周期(默认每小时)创建时间线快照;每次执行zypper安装或删除软件包时,还会自动创建pre和post两个配对快照。
btrfs快照采用写时复制(COW)机制,创建快照本身几乎不占空间,但随着后续系统数据不断修改,旧的快照会持有大量被覆盖前的数据块。这意味着快照存在的时间越久、系统变更越频繁,被钉住的空间就越多。表面上df命令显示的磁盘占用已经包含了这些快照数据,普通用户很难察觉问题,直到某天空间彻底耗尽。
Snapper其实内置了自动清理逻辑,核心在于每个配置(如root配置)的参数文件/etc/snapper/configs/root,以及systemd定时器snapper-cleanup.timer。下面我们分别展开讲解。
配置文件中的关键清理参数
打开/etc/snapper/configs/root,可以看到大量以大写字母命名的参数。与自动清理直接相关的有这几组,逐一说明其含义和推荐值。
第一组是编号快照限制。NUMBER_LIMIT定义保留的编号快照对数量上限(注意是pre/post对数,不是快照总数),NUMBER_LIMIT_IMPORTANT定义其中标记为important的快照对上限。超出限制后,Snapper会优先删除最旧的普通快照,而important快照只有在总数超限时才会被动清理,这个机制保证了关键的系统更新回滚点不会被轻易丢弃。
# 查看root配置中的限制参数
sudo snapper -c root get-config | grep -i limit
# 修改编号快照上限,比如只保留最近10对
sudo snapper -c root set-config NUMBER_LIMIT=10 \
NUMBER_LIMIT_IMPORTANT=5第二组是时间线快照限制。TIMELINE_LIMIT_HOURLY、TIMELINE_LIMIT_DAILY、TIMELINE_LIMIT_WEEKLY、TIMELINE_LIMIT_MONTHLY、TIMELINE_LIMIT_YEARLY分别控制各粒度保留的快照数量。一个常见且均衡的设置是:每小时保留5个、每天保留7个、每周保留4个、每月保留3个、每年不保留,这样既能在近期提供密集的恢复点,又保留了更长周期的历史记录。
sudo snapper -c root set-config \
TIMELINE_LIMIT_HOURLY=5 \
TIMELINE_LIMIT_DAILY=7 \
TIMELINE_LIMIT_WEEKLY=4 \
TIMELINE_LIMIT_MONTHLY=3 \
TIMELINE_LIMIT_YEARLY=0第三组是pre/post快照的处理。EMPTY_PRE_POST决定如何处理没有发生实际变更的空快照对,设为cleanup表示直接清理掉;如果希望保留痕迹用于审计,可以设为log,只在日志中记录而不保留快照。对于经常执行无变更zypper操作的用户,启用cleanup能明显减少无效快照的堆积。
定时任务的运行原理与手动触发
参数设置好后,还需要确保清理任务真正在运行。openSUSE通过systemd timer驱动整个清理流程,可以用以下命令检查状态:
systemctl status snapper-cleanup.timer systemctl status snapper-timeline.timer # 手动触发一次清理验证效果 sudo snapper -c root cleanup number sudo snapper -c root cleanup timeline
snapper-cleanup.timer默认每天执行一次snapper.service,后者会对所有配置执行number和timeline两种清理算法。snapper-timeline.timer则默认每小时创建时间线快照。如果你的系统空间紧张,或者更新非常频繁,可以适当调高cleanup的执行频率,例如通过override文件改成每小时执行一次。
需要特别注意,清理算法在删除pre快照时,会同时检查配对的post快照。pre/post是成对存在的,删除时必须成对处理,这也是为什么NUMBER_LIMIT用对数作为单位的原因。理解这一点有助于在手动删除时避免误操作。
磁盘空间紧张时的应急与调优
当根分区已经接近满载,自动清理可能来不及救场,此时可以手动批量删除最旧的快照:
# 查看现有快照列表 sudo snapper -c root list # 删除编号为1的快照(pre/post会成对处理) sudo snapper -c root delete 1 # 一次性删除1到20号快照 sudo snapper -c root delete 1-20
对于Tumbleweed滚动发行版用户,由于系统更新极其频繁,pre/post快照产生速度非常快,建议将NUMBER_LIMIT控制在10以内,同时合理设置空快照清理策略。Leap用户更新节奏较慢,可以适当放宽限制以保留更多回滚点。无论哪个版本,都建议定期用df -h /检查根分区占用情况,防患于未然。
另一个实用技巧是启用btrfs配额组来精确观察每个快照的实际占用:sudo btrfs qgroup show /可以列出各子卷的独占空间。虽然启用qgroup会带来轻微的性能开销,但在排查快照到底吃了多少空间时非常直观。此外,删除快照后空间不会立即释放,btrfs需要在后台清理数据引用,此时执行sudo btrfs subvolume sync /可以等待清理完成后再查看真实的可用空间。
总结一下,Snapper的自动清理并不神秘:改好配置文件里的各项LIMIT参数,确认snapper-cleanup.timer处于active状态,再配合定期检查磁盘占用和必要时手动批量删除,就能让快照机制长期稳定运行,既享受回滚带来的安全感,又不必担心磁盘空间失控。