Hans-Juergen Schoenig:为什么 pg_hardstorage 没有增量链

Hans-Juergen Schoenig:为什么 pg_hardstorage 没有增量链

💡 原文英文,约600词,阅读约需2分钟。
📝

内容提要

pg_hardstorage 采用内容寻址存储,按 SHA-256 引用数据块,不依赖链式增量备份,因此任一备份损坏或删除旧备份均不影响其他备份。实测 487 GiB 数据去重率 87.5%,存储从 89.2 TiB 降至 12.4 TiB。代价是备份时需读取完整数据目录,快照加速功能尚未发布。

🔎

延伸解读

链式增量备份的脆弱性

文章指出,链式增量备份(如 pgBackRest 默认模式、Barman 增量模式)中,每个增量都直接引用前一个备份,形成依赖链。这种结构在正常工作时没问题,但一旦链中任一备份损坏,下游所有备份都会失效。更危险的是,问题往往在恢复时才暴露,尤其是在凌晨三点的紧急恢复场景中。pg_hardstorage 通过内容寻址避免了这种单点故障。

内容寻址如何消除链依赖

pg_hardstorage 的清单文件通过 SHA-256 哈希引用数据块,而不是引用前一个清单。每个块的文件名就是其哈希值,因此两个备份共享数据时,是在存储层共享块,而非通过“父指针”关联。删除旧备份不会影响新备份的块,直到垃圾回收发现零引用。这种设计让备份之间完全独立,删除历史中的任意备份都不会破坏其他备份。

去重效果与存储节省

在 487 GiB 的生产级数据集上,每小时备份持续一周,总块数为 1,247,883,唯一块数为 156,423,去重率达 87.5%。总存储占用从原始 89.2 TiB 降至 12.4 TiB。每次备份新增块数约为 1,200 ± 400。这表明内容寻址在去重方面与链式增量备份具有竞争力,同时消除了链依赖。

当前代价与未来改进

pg_hardstorage 目前每次备份都需要读取完整的 PostgreSQL 数据目录,然后与块池进行去重。对于 100 TB 的数据库和慢速存储,这并非没有成本。作者正在开发基于文件系统级写时复制(COW)快照的快速路径,但尚未发布。因此,当前的主要代价是源端 I/O 略高,换来的是可独立检查的清单格式、无隐藏顺序约束的删除模型,以及无法被破坏的备份链。

❓

Q&A

pg_hardstorage 为什么没有增量链?

pg_hardstorage 采用内容寻址存储,每个数据块以 SHA-256 哈希命名,备份清单直接引用这些块,而不是引用前一个备份。因此不存在链式依赖,任一备份损坏或删除旧备份都不会影响其他备份。

pg_hardstorage 的去重效果如何?

在 487 GiB 生产级数据上,每小时备份一周,去重率达到 87.5%,总存储从原始 89.2 TiB 降至 12.4 TiB。

pg_hardstorage 的备份性能有什么代价?

目前每次备份都需要读取完整的 PostgreSQL 数据目录,然后与块池进行去重。对于 100 TB 的数据库在慢速存储上,这会产生额外的 I/O 开销。快照感知的快速路径尚未发布。

pg_hardstorage 与链式增量备份相比有什么优势?

链式增量备份中,任何一个备份损坏都会导致下游所有备份失效。pg_hardstorage 没有链式依赖,删除中间备份不会破坏其他备份,且清单格式可以用 jq 直接查看。

pg_hardstorage 的清单格式是什么样的?

清单是一个 JSON 对象,包含备份 ID 和一个 chunks 数组,数组元素是数据块的 SHA-256 哈希值。例如:{"id": "prod-2026-05-02-0334", "chunks": ["7e1f2a…ab", "9c4d3b…12", "2faabc…77"]}。

pg_hardstorage 删除旧备份会影响新备份吗?

不会。删除旧备份后,新备份的块会保留,直到垃圾回收发现这些块没有任何引用时才会被清理。

🏷️

标签

➡️

继续阅读