登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux tar --listed-incremental 怎样制作增量归档

来源:17golang原创

时间:2026-10-27 00:38:59 284浏览 收藏

我第一次把目录备份改成增量方式时,最容易混淆的是“增量”到底由谁判断。tar 并不是凭归档文件名猜测变化,而是把上一次扫描得到的目录状态保存到快照文件,再用 --listed-incremental 对比这个快照。最小可用方案是:先生成一次 level 0 基线归档,随后继续使用同一个快照文件创建增量归档,恢复时按基线到增量的顺序全部解开。

官方地址:https://www.gnu.org/software/tar/manual/

下面只讨论 GNU tar 的 --listed-incremental,不把它扩展成通用备份系统。命令中的目录名可以替换成自己的数据目录,但一次归档链应该始终使用相同的目录根和快照文件。

先把三类文件的职责分开

这套方式至少涉及三类文件:

  • 数据目录:真正要归档的目录,例如 ./project。
  • 快照文件:例如 ./state/project.snar,由 GNU tar 保存目录状态,用来判断后续哪些内容新增、修改或删除。
  • 归档文件:例如 archive-0.tar、archive-1.tar,恢复时需要按时间顺序组合。

第一次使用不存在的快照文件时,tar 会把这次归档作为 level 0。之后快照文件会被更新,因此它不是“只读配置”,而是这条归档链的状态文件。它必须和归档文件一起纳入保管范围;如果只留下某个增量归档,通常无法独立得到完整目录状态。

tar listed-incremental 使用快照文件比较目录并生成 level 0 与 level 1 归档的结构说明图
图1:结构说明图,展示 GNU tar 从源目录读取快照文件、生成基线和增量归档的关系,不是运行截图。

第一次运行先创建 level 0 基线

先准备一个专门保存快照和归档的目录。不要把快照文件放进正在被归档的目录里,否则快照本身可能成为输入的一部分。

# 创建独立的归档状态目录,避免快照文件混入数据目录
mkdir -p ./backup-state

# 第一次运行没有 snapshot 文件,tar 会建立 level 0 基线归档
tar --create \
  --file=./backup-state/archive-0.tar \
  --listed-incremental=./backup-state/project.snar \
  ./project

这条命令的关键不是 archive-0.tar 这个名字,而是 --listed-incremental 后面指向的快照文件。执行后要同时保留 archive-0.tar 和 project.snar。如果想明确强制重新做基线,可以使用 --level=0,但要把它当成一次新的备份基点处理,避免覆盖掉仍在使用的快照状态。

第二次运行复用快照文件

在 ./project 下新增或修改少量内容后,仍然指向同一个 project.snar:

# 复用上一次的快照,tar 只记录相对基线已变化的目录项
tar --create \
  --file=./backup-state/archive-1.tar \
  --listed-incremental=./backup-state/project.snar \
  ./project

第二次运行时,tar 会更新快照文件。新增目录可能连同目录中的文件一起进入增量归档;删除也会通过 GNU tar 的增量元数据表达。不要把“文件数量少”理解成“归档可以脱离基线独立恢复”,它仍然依赖 archive-0.tar。

我在实际排期中会把快照文件当成一个需要版本化的状态:归档命令运行前先确保上一次归档已经完成,归档文件和快照文件的备份动作也要有一致的时间点。若希望从同一个基线制作多个互不影响的分支,可以先复制快照文件,再让不同任务使用各自的副本:

# 复制基线快照,避免两个归档任务共同改写同一份状态
cp ./backup-state/project.snar ./backup-state/project-snar-branch-a.snar

# 分支任务使用自己的快照副本,归档链仍从同一个基线出发
tar --create \
  --file=./backup-state/archive-branch-a-1.tar \
  --listed-incremental=./backup-state/project-snar-branch-a.snar \
  ./project

恢复时按 level 0 到增量的顺序

恢复阶段不需要原来的 .snar 文件。GNU tar 会从归档内部保存的增量元数据读取删除和目录状态信息;常见写法是把 --listed-incremental 指向 /dev/null,并严格按创建顺序依次解开:

# 先恢复完整基线,建立恢复目录的初始状态
mkdir -p ./restore
tar --extract \
  --listed-incremental=/dev/null \
  --file=./backup-state/archive-0.tar \
  --directory=./restore

# 再按时间顺序叠加增量归档,得到最后一次归档时的状态
tar --extract \
  --listed-incremental=/dev/null \
  --file=./backup-state/archive-1.tar \
  --directory=./restore

如果还有 archive-2.tar,继续放在 archive-1.tar 后面。顺序反过来会让增量内容缺少基线,或者让较早的状态覆盖较新的状态。恢复前要确认目标目录是允许被归档元数据调整的目录,因为增量恢复会尝试把目录还原到创建归档时的精确状态,包含清理当时不存在的成员。

GNU tar 按 level 0、level 1、level 2 顺序恢复并使用归档内元数据的结构说明图
图2:结果说明图,展示增量归档的恢复顺序和快照文件只参与创建的边界,不是运行截图。

用双 verbose 查看增量归档记录

只看普通文件名列表,往往看不出增量归档记录了哪些目录状态。GNU tar 手册建议在列出时同时使用 --incremental 和两个 --verbose:

# 查看归档中的增量目录信息,便于判断成员是存在、缺失还是目录
tar --list \
  --incremental \
  --verbose \
  --verbose \
  --file=./backup-state/archive-1.tar

输出中的标记是给人和程序读取的目录状态信息。它比单纯比较归档文件大小更适合用来理解“为什么这次没有把整个目录重新写入”。这一步只是读取归档,不会让原快照文件重新参与恢复。

这几个边界不处理,增量结果会变得难以解释

不要在归档过程中随意改时间戳

增量判断依赖时间戳。归档期间修改文件时间,或把系统时钟向后调整,都可能让结果不可靠。生产任务应尽量避免在扫描同一目录时批量重写 mtime,并保证时间同步策略稳定。

跨 NFS 或 LVM 快照时注意设备号

快照中还会记录设备号。NFS 自动挂载、LVM 快照卷等场景可能让设备号看起来发生变化,造成未修改文件被重复归档。这类场景可以显式使用 --no-check-device:

# 设备号不稳定时,避免把设备号变化直接当成目录变化
tar --create \
  --file=./backup-state/archive-1.tar \
  --listed-incremental=./backup-state/project.snar \
  --no-check-device \
  ./project

它是针对设备号比较的选择,不等于关闭所有变化判断。应结合实际挂载方式决定是否启用,并把这个参数固定在同一条归档链的配置里。

增量归档不是所有 tar 都能读

--listed-incremental 使用 GNU tar 的扩展格式,非 GNU 版本的 tar 可能无法正确读取。跨机器恢复时,应提前确认目标环境使用 GNU tar;不要把一个普通 POSIX tar 工具能解开普通归档,推断为它也能解开这条增量归档链。

我的取舍:把快照文件和归档链一起管理

对我来说,最稳妥的目录布局是把数据、快照、归档和恢复演练分开:数据目录只负责业务文件,快照文件与归档文件一起进入备份保管,恢复演练使用临时目录。每次新增一层增量,就记录它对应的基线归档和创建时间;需要迁移时,把 GNU tar 的版本与命令参数也记在任务配置中。

可以用下面的速查表做决定:

目标做法重点边界
第一次建立备份链不存在的快照文件 + --listed-incremental得到 level 0,快照文件开始产生
后续只归档变化继续使用同一快照文件快照会更新,不能并发写同一份状态
恢复到最后状态level 0 后按顺序解开所有增量恢复不需要原快照,但不能跳过中间层
设备号不稳定考虑 --no-check-device只改变设备号比较策略,不是万能去重

归档前真正要确认的只有三件事:快照文件是否属于这条归档链、归档任务是否会并发改写它、恢复环境是否具备 GNU tar。把这三个问题处理好,--listed-incremental 就能稳定地承担“基线 + 变化层”的目录归档任务。

相关问题

可以只恢复 archive-1.tar 吗?

不建议。它通常只包含相对快照发生变化的内容,完整状态需要先恢复对应的 level 0,再按顺序应用后续增量。

恢复时一定要找到原来的 snar 文件吗?

不需要。创建阶段依赖快照文件,提取阶段可以把参数指向 /dev/null,因为恢复所需的增量元数据已写入归档。

为什么第二次归档仍然很大?

先排查时间戳是否被批量更新、设备号是否发生变化、归档根目录是否改变,以及快照文件是否被删除或换成了另一份。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>