删除 restic 备份快照

备份空间总是有限的,因此 restic 支持删除旧快照。你可以手动指定要删除的快照 ID,也可以用保留策略决定哪些快照应当移除。删除过程包含两个先后执行的步骤:用 forget 移除快照记录,再用 prune 删除仅被这些已移除快照引用的数据。给 forget 添加 --prune,可以在实际移除了快照后自动执行 prune。

清理所需时间取决于快照数量与数据量,可能很长。执行 prune 时仓库会锁定,备份无法完成。应安排足够时间,避免影响正常备份。清理后建议运行 restic check,以便及时发现仓库内部数据结构受损。

删除单个快照

用 snapshots 列出仓库中的快照:

$ restic -r /srv/restic-repo snapshots
enter password for repository:
ID        Date                 Host      Tags  Directory
----------------------------------------------------------------------
40dc1520  2015-05-08 21:38:30  kasimir         /home/user/work
79766175  2015-05-08 21:40:19  kasimir         /home/user/work
bdbd3439  2015-05-08 21:45:17  luigi           /home/art
590c8fc8  2015-05-08 21:47:38  kazik           /srv
9f0bc19e  2015-05-08 21:46:11  luigi           /srv

要删除 /home/art 的快照,向 forget 传入相应 ID:

$ restic -r /srv/restic-repo forget bdbd3439
enter password for repository:
removed snapshot bdbd3439

随后该快照就不在列表中了:

$ restic -r /srv/restic-repo snapshots
enter password for repository:
ID        Date                 Host     Tags  Directory
----------------------------------------------------------------------
40dc1520  2015-05-08 21:38:30  kasimir        /home/user/work
79766175  2015-05-08 21:40:19  kasimir        /home/user/work
590c8fc8  2015-05-08 21:47:38  kazik          /srv
9f0bc19e  2015-05-08 21:46:11  luigi          /srv

但该快照文件引用的数据仍在仓库中。要回收不再被引用的数据,需要运行 prune:

$ restic -r /srv/restic-repo prune
enter password for repository:
repository 33002c5e opened successfully
loading all snapshots...
loading indexes...
finding data that is still in use for 4 snapshots
[0:00] 100.00%  4 / 4 snapshots
searching used packs...
collecting packs for deletion and repacking
[0:00] 100.00%  5 / 5 packs processed
to repack:            69 blobs / 1.078 MiB
this removes:         67 blobs / 1.047 MiB
to delete:             7 blobs / 25.726 KiB
total prune:          74 blobs / 1.072 MiB
remaining:            16 blobs / 38.003 KiB
unused size after prune: 0 B (0.00% of remaining size)
repacking packs
[0:00] 100.00%  2 / 2 packs repacked
rebuilding index
[0:00] 100.00%  3 / 3 packs processed
deleting obsolete index files
[0:00] 100.00%  3 / 3 files deleted
removing 3 old packs
[0:00] 100.00%  3 / 3 files deleted
done

完成后,仓库占用的空间会缩小。

也可以给 forget 加上 --prune,自动完成这两个步骤:

$ restic forget --keep-last 1 --prune
snapshots for host mopped, directories /home/user/work:

keep 1 snapshots:
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
4bba301e  2017-02-21 10:49:18  mopped                  /home/user/work
remove 1 snapshots:
ID        Date                 Host        Tags        Directory
----------------------------------------------------------------------
8c02b94b  2017-02-21 10:48:33  mopped                  /home/user/work
1 snapshots have been removed, running prune
loading all snapshots...
loading indexes...
finding data that is still in use for 1 snapshots
[0:00] 100.00%  1 / 1 snapshots
searching used packs...
collecting packs for deletion and repacking
[0:00] 100.00%  5 / 5 packs processed
to repack:           69 blobs / 1.078 MiB
this removes         67 blobs / 1.047 MiB
to delete:            7 blobs / 25.726 KiB
total prune:         74 blobs / 1.072 MiB
remaining:           16 blobs / 38.003 KiB
unused size after prune: 0 B (0.00% of remaining size)
repacking packs
[0:00] 100.00%  2 / 2 packs repacked
rebuilding index
[0:00] 100.00%  3 / 3 packs processed
deleting obsolete index files
[0:00] 100.00%  3 / 3 files deleted
removing 3 old packs
[0:00] 100.00%  3 / 3 files deleted
done

按策略删除快照

手工删除既费时又容易出错。restic 可以通过一个或多个 --keep-* 选项定义保留策略,例如保留多少个按小时、日、周、月或年选出的快照,删除其余快照。

警告:若在只允许追加写入的仓库中按策略移除快照,需要考虑下文介绍的安全问题。

注意:forget 始终支持 --dry-run,只显示准备执行的操作,不实际移除快照。

forget 接受以下策略选项:

  • --keep-last n:保留最新的 n 个快照。
  • --keep-hourly n:对最近 n 个存在快照的小时,每小时只保留最新快照。
  • --keep-daily n:对最近 n 个存在快照的日期,每天只保留最新快照。
  • --keep-weekly n:对最近 n 个存在快照的星期,每周只保留最新快照。
  • --keep-monthly n:对最近 n 个存在快照的月份,每月只保留最新快照。
  • --keep-yearly n:对最近 n 个存在快照的年份,每年只保留最新快照。
  • --keep-tag:保留符合至少一个标签列表的快照。一次选项中的逗号分隔标签采用 AND,必须全部匹配;重复给出该选项时,各列表采用 OR,匹配任意列表即可。若一组快照没有任何一个符合标签策略,导致整组都会被删除,forget 会报错退出。
  • --keep-within duration:保留时间戳位于最新快照之前指定时长以内的全部快照。时长以年、月、日和小时表示,例如 2y5m7d3h 表示最新快照之前两年、五个月、七天、三小时。
  • --keep-within-hourly duration:在距最新快照指定时长内保留按小时选出的快照;时长写法同 --keep-within,小时快照的选择方式同 --keep-hourly。
  • --keep-within-daily duration:在距最新快照指定时长内保留按日选出的快照。
  • --keep-within-weekly duration:在距最新快照指定时长内保留按周选出的快照。
  • --keep-within-monthly duration:在距最新快照指定时长内保留按月选出的快照。
  • --keep-within-yearly duration:在距最新快照指定时长内保留按年选出的快照。

注意:按日历周期计算的 --keep-{hourly,daily,...} 使用自然时间边界,而不是以运行 forget 的时刻倒推。周从星期一00:00到星期日23:59,日从00:00到23:59,小时从整点到该小时的59分。它们只统计实际存在快照的周期。值 unlimited 表示永远保留,也就是全部保留。

注意:与时长有关的 --keep-{within-,}* 选项忽略时间戳位于未来的快照,因此不会移除这些快照;这里的未来相对于运行 forget 的时刻。

注意:若快照不足以覆盖某个基于时长的选项,会额外保留最旧的快照,并在输出中标为 oldest,例如 oldest hourly snapshot。

注意:--keep-tag '' 只匹配没有标签的快照。

按策略运行 forget 时,restic 会读取全部快照,默认按主机名和路径分组,再对每组单独应用策略,避免意外删除其他备份集。可以用 --group-by 更改分组,例如 --group-by paths,tags 表示按路径和标签分组。--group-by ''(空字符串)会关闭分组,把策略应用于所有主机、路径和标签的快照。通常,backup 命令也应采用相同的 --group-by 设置。

还可以用 --host 限定主机,或用 --tag 筛选标签。单次 --tag 中以逗号分隔的标签必须全部匹配;多次使用 --tag 时,匹配任意标签列表便会纳入处理。

例如,以下命令对含 foo 标签的快照,只保留最新一个:

$ restic forget --tag foo --keep-last 1

以下命令对含 foo 或 bar 标签的快照,只保留最新一个:

$ restic forget --tag foo --tag bar --keep-last 1

以下命令只处理同时含 foo 和 bar 标签的快照,并只保留最新一个:

$ restic forget --tag foo,bar --keep-last 1

要只处理未打标签的快照,把标签设为空字符串:

$ restic forget --tag '' --keep-last 1

假设你每天备份一次,持续100年。forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 75 会保留最近7个每日快照,以及4个周末快照,因为7个每日快照已包含1个每周快照。另外保留12或11个月末快照,具体取决于是否与每日或每周快照重合;最后保留75或74个年末快照,同样取决于是否与已保留快照重合。其余快照会被移除。

如果备份不规律,--keep-daily 7 的7个每日快照可能分布在更长时间内。如果想保留最近一周的每日快照、最近一个月的每周快照、最近一年的每月快照,以及最近75年的每年快照,可以用 forget --keep-within-daily 7d --keep-within-weekly 1m --keep-within-monthly 1y --keep-within-yearly 75y。1w 不是合法时长,应使用 7d。

快照会对所有 --keep-* 条件进行评估,只需满足任意一个条件就会保留,也就是 OR。最新快照可能同时符合每小时、每日、每周等多个条件。

看一个具体例子:过去两周的每个工作日都有一次备份,每个星期五再额外备份一次:

$ restic snapshots
repository f00c6e2a opened successfully
ID        Time                 Host        Tags        Paths
---------------------------------------------------------------
60e5c031  2025-04-21 11:00:00  mopped                  /home/user/work
1dccffe9  2025-04-22 11:00:00  mopped                  /home/user/work
90a5c949  2025-04-23 11:00:00  mopped                  /home/user/work
79580708  2025-04-24 11:00:00  mopped                  /home/user/work
8a603ddf  2025-04-25 11:00:00  mopped                  /home/user/work
ae33bf10  2025-04-25 23:00:00  mopped                  /home/user/work
fb8b1418  2025-04-28 11:00:00  mopped                  /home/user/work
1db188b4  2025-04-29 11:00:00  mopped                  /home/user/work
7baa4f28  2025-05-01 11:00:00  mopped                  /home/user/work
05c48af3  2025-05-02 11:00:00  mopped                  /home/user/work
ad72e262  2025-05-02 23:00:00  mopped                  /home/user/work
---------------------------------------------------------------
11 snapshots

但上一周的星期三没有备份。forget --keep-daily 5 会在最近5个有快照的日期中,每天保留最新一个,移除其余快照:

$ restic forget --keep-daily 5 --dry-run
repository f00c6e2a opened successfully
Applying Policy: keep 5 daily snapshots
keep 5 snapshots:
ID        Time                 Host        Tags        Reasons         Paths
-------------------------------------------------------------------------------
8a603ddf  2025-04-25 23:00:00  mopped                  daily snapshot  /home/user/work
fb8b1418  2025-04-28 11:00:00  mopped                  daily snapshot  /home/user/work
1db188b4  2025-04-29 11:00:00  mopped                  daily snapshot  /home/user/work
7baa4f28  2025-05-01 11:00:00  mopped                  daily snapshot  /home/user/work
ad72e262  2025-05-02 23:00:00  mopped                  daily snapshot  /home/user/work
-------------------------------------------------------------------------------
5 snapshots
remove 6 snapshots:
ID        Time                 Host        Tags        Paths
---------------------------------------------------------------
60e5c031  2025-04-21 11:00:00  mopped                  /home/user/work
1dccffe9  2025-04-22 11:00:00  mopped                  /home/user/work
90a5c949  2025-04-23 11:00:00  mopped                  /home/user/work
79580708  2025-04-24 11:00:00  mopped                  /home/user/work
8a603ddf  2025-04-25 11:00:00  mopped                  /home/user/work
05c48af3  2025-05-02 11:00:00  mopped                  /home/user/work
---------------------------------------------------------------
6 snapshots

因为星期三缺少备份,它会保留前一个星期五的快照。如果改用 forget --keep-within-daily 7d,则只在最近7天内每天最多保留一个快照。本例中,无论第二周有多少快照,第一周的快照都不会保留:

$ restic forget --keep-within-daily 7d --dry-run
repository f00c6e2a opened successfully
Applying Policy: keep daily snapshots within 7d
keep 4 snapshots:
ID        Time                 Host        Tags        Reasons         Paths
-------------------------------------------------------------------------------
fb8b1418  2025-04-28 11:00:00  mopped                  daily within 7d  /home/user/work
1db188b4  2025-04-29 11:00:00  mopped                  daily within 7d  /home/user/work
7baa4f28  2025-05-01 11:00:00  mopped                  daily within 7d  /home/user/work
ad72e262  2025-05-02 23:00:00  mopped                  daily within 7d  /home/user/work
-------------------------------------------------------------------------------
4 snapshots
remove 7 snapshots:
ID        Time                 Host        Tags        Paths
---------------------------------------------------------------
60e5c031  2025-04-21 11:00:00  mopped                  /home/user/work
1dccffe9  2025-04-22 11:00:00  mopped                  /home/user/work
90a5c949  2025-04-23 11:00:00  mopped                  /home/user/work
79580708  2025-04-24 11:00:00  mopped                  /home/user/work
8a603ddf  2025-04-25 11:00:00  mopped                  /home/user/work
ae33bf10  2025-04-25 23:00:00  mopped                  /home/user/work
05c48af3  2025-05-02 11:00:00  mopped                  /home/user/work
---------------------------------------------------------------
7 snapshots

删除全部快照

出于安全考虑,restic 不执行“空”策略。例如,--keep-last 0 不会清空仓库,而会提示不移除任何快照。要删除全部快照,可以先用 --keep-last 1,最后再向 forget 传入剩余快照的 ID,手动移除它。

从 restic 0.17.0 开始,还可以用 --unsafe-allow-remove-all 删除某个主机、标签或路径下的全部快照。该选项必须与主机、路径或标签筛选器一起使用。例如,forget --tag example --unsafe-allow-remove-all 会移除所有含 example 标签的快照。

追加写入模式的安全问题

注意:在只允许追加写入的仓库中,移除快照时应特别采用 forget 的 --keep-within 选项。

为了防止被攻破的备份客户端删除备份,例如感染勒索软件的客户端,仓库服务或后端可以提供追加写入模式:允许读取和添加数据,拒绝删除与覆盖。restic 的 rest-server 支持这一模式,但其他常见后端很少支持。对于这些后端,可在备份客户端与服务之间加入 rclone。

移除快照并回收空间时,forget 和 prune 需要完整的读、写、删除权限。如果攻击者取得这种权限,追加写入模式的保护自然失效。因此,推荐使用独立且安全保护充分的客户端执行这些管理任务和维护命令。

即使启用了追加写入模式,也用独立客户端管理,攻击者仍可能加入垃圾快照,改变快照列表。管理员若直接执行某些 --keep-* 策略,就可能移除所有合法快照,只留下攻击者的无用快照。

例如,策略保留3个每周快照。攻击者可以在最近3周分别添加空快照,利用 backup 的 --time 选项,让时间戳稍晚于合法快照,但仍位于对应星期。管理员或计划任务下次执行保留策略时,每周只会保留最新的攻击者快照,合法快照就会被移除。即使尚未执行 prune,恢复数据也会很麻烦,并损失部分元数据。

采用 --keep-within 可以在指定时间范围内同时保留攻击者与合法快照。只要运行 forget 时系统时间正确,管理员就有机会通过异常的快照数量或可疑时间戳发现备份问题与受攻破的主机。不过保护只在指定时长内有效:如果最后一个正常快照已过去8天,而策略只有 forget --keep-within 7d,攻击者仍可利用机会让全部合法快照被移除。

定制清理行为

先了解清理过程:

  1. 扫描全部快照及快照中的目录,确认哪些数据仍被使用。
  2. 对仓库中的每个文件,判断是全部使用、部分使用还是完全未使用。
  3. 完全未使用的文件标记为删除;完全使用的文件保留;部分使用的文件按用户选项决定保留还是重打包。重打包需要从仓库存储下载文件,再把需要的数据上传回去,对远程仓库可能很耗时。
  4. 确定计划后,prune 执行重打包、更新索引并删除过时文件。

prune 支持以下选项:

  • --max-unused limit:允许仓库中保留一定量的未使用数据,从而可以保留部分使用的文件,减少重打包。限制可以是绝对大小,例如 200M;如果想尽量减少仓库占用,设为 0。也可以是总大小的比例,例如 10%:清理后仓库为500MB时,最多允许50MB未使用数据。值 unlimited 不限制部分使用的文件,只要其中有数据仍被引用就保留,可尽量降低清理耗时与带宽,但元数据仍会重打包。restic 会在满足限制的同时尽量少重打包,默认值为5%。
  • --max-repack-size size:限制要重打包的文件总大小。prune 先保存全部重打包结果,最后才删除旧文件;若预计重打包量大且担心空间不足,这个选项会很有用。
  • --repack-cacheable-only:设为 true 时,只重打包包含元数据、可存入缓存的文件;其他数据包不重打包。这样可以只使用缓存数据,快速完成,但未使用数据可能超过 --max-unused 的限制。默认 false。
  • --repack-smaller-than:重打包所有小于指定大小的数据包,使原先使用较小 --pack-size 创建的包可以合并为更大的包。
  • --dry-run:仅显示清理计划。
  • --verbose:提供更详细的清理统计。

处理“没有可用空间”错误

仓库占满磁盘或配额时,prune 可能无法释放空间。它的常规设计保证无论何时被中断,仓库仍可使用,但这也意味着需要一些临时工作空间。

多数情况下,可以用 prune --max-repack-size 0 尽量减少临时空间;restic 0.13.0 之前的版本应使用 prune --max-repack-size 1。前提是已用 forget 移除了一些快照,清理才能真正删除不再引用的数据。如果清理成功但空间仍很少,可再移除几个快照,再次清理。

如果仍无法完成,最后手段是 prune --unsafe-recover-no-free-space SOME-ID,允许在几乎没有空间时清理。但失败可能使仓库暂时不可用,执行前必须确保与仓库存储的连接稳定。失败时,可能需要手动删除仓库 index/ 中全部文件,再运行 restic repair index。

为防止误用,需要先以占位符 SOME-ID 运行该选项,然后按照程序提示把它替换为要求的 ID。


作者:restic 项目贡献者。来源:Removing backup snapshots,restic 0.19.1,对应 v0.19.1 文档源码。2026-10-03 完整译为中文,代码与输出保留原文,仅转换排版;未执行任何命令。本文依据该源文件所属仓库的 BSD 2-Clause License提供,完整版权、条件与免责声明见随附 LICENSE.txt。Copyright (c) 2014, Alexander Neumann alexander@bumpern.de,All rights reserved。内容按现状提供,无任何明示或暗示保证,权利人与贡献者不承担许可所述责任。本文无截图或生成图像。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容