pgBackRest 压缩怎么选:别为最后一点空间浪费太多 CPU

2026-09-17 25 预计阅读时间: 1 分钟
来源: percona.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

备份压缩不是越高越好。更高的压缩级别可能让仓库再小一点,却会显著增加备份时间和 CPU 消耗,还可能与数据库业务争抢计算资源。对 pgBackRest 而言,低级别 Zstandard 通常落在更实用的平衡点上,而默认的 zst(3) 已经非常接近这个甜蜜点。

真正要优化的不是压缩率,而是备份链路

评估压缩参数时,只看最终文件大小很容易得出错误结论。一次 PostgreSQL 备份至少涉及四类成本:

  • 从数据库数据目录读取页面的 I/O;
  • 压缩进程消耗的 CPU;
  • 将备份写入本地磁盘、对象存储或远程仓库的吞吐;
  • 恢复时的读取、传输和解压成本。

如果备份仓库位于速度较慢的网络或按容量计费的对象存储中,多消耗一些 CPU 可能值得。反过来,如果数据库主机已经接近 CPU 饱和,或者备份窗口很紧,高压缩级别节省的少量空间通常不划算。

这也是 Zstandard 低级别有吸引力的原因:它能以相对温和的 CPU 成本获得较好的压缩效果。继续提高级别时,压缩文件仍会变小,但收益往往开始递减。来源给出的核心判断是:低级别 Zstandard 是合理的甜蜜点,pgBackRest 默认的 zst(3) 已经处于这一范围。

为什么不应该直接把压缩级别拉满

压缩级别通常不是线性旋钮。把级别从 1 调到 3,与从 3 调到更高级别,带来的收益并不相同。后者可能明显增加 CPU 时间,却只减少很小比例的仓库占用。

生产环境中还需要考虑几个容易被忽略的变量:

  • 并行度process-max 越高,备份吞吐可能越高,但瞬时 CPU 压力也会增加。
  • 数据类型:文本、重复值和稀疏数据通常更容易压缩;已经压缩的图片、归档文件或加密数据收益有限。
  • 备份类型:全量、差异和增量备份的数据组成不同,不能只测一次全量就推断所有任务。
  • 仓库位置:本地 NVMe、跨区域网络和对象存储面对的瓶颈完全不同。
  • 恢复目标:压缩设置不能只服务于备份窗口,还要验证恢复时间目标 RTO。

因此,最合适的级别不是“产生最小文件的级别”,而是“在满足备份窗口和恢复目标的前提下,让总成本最低的级别”。

可以这样配置 zst(3)

下面是一份可改造的 pgBackRest 配置。运行前需要按实际 PostgreSQL 版本、数据目录和仓库路径修改相应字段:

[global]
repo1-path=/backup/pgbackrest
repo1-retention-full=2

# Zstandard,级别 3
compress-type=zst
compress-level=3

# 根据主机 CPU 和备份窗口调整;测试时应保持不变
process-max=4

[main]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

配置文件通常可保存为 /etc/pgbackrest/pgbackrest.conf。pgBackRest 会在每次命令执行时读取配置,不需要为修改压缩参数重启 PostgreSQL。

创建 stanza 并执行一次全量备份的命令如下:

sudo -u postgres pgbackrest --stanza=main stanza-create
sudo -u postgres pgbackrest --stanza=main check
sudo -u postgres pgbackrest --stanza=main --type=full backup
sudo -u postgres pgbackrest --stanza=main info

不要在没有恢复验证的情况下直接替换生产参数。至少先在测试环境中完成一次备份和恢复演练。

用自己的数据做一轮可重复的对比

不同数据库的可压缩性差异很大。下面的脚本会分别测试 zst(1)zst(3)zst(6)gz(6),记录墙钟时间、用户态 CPU 时间、内核态 CPU 时间、CPU 利用率及仓库字节数。

这是一个测试环境脚本。它通过 --archive-check=n 避免测试仓库与现有 WAL 归档配置冲突,因此生成的备份只能用于压缩性能比较,不能作为正式恢复副本。执行前还应确保 /var/tmp/pgbackrest-bench 有足够空间。

#!/usr/bin/env bash
set -euo pipefail

STANZA="${STANZA:-main}"
BASE="${BASE:-/var/tmp/pgbackrest-bench}"

# 算法和级别。可以删除不需要的组合,或增加更多 zst 级别。
cases=(
  "zst 1"
  "zst 3"
  "zst 6"
  "gz 6"
)

mkdir -p "$BASE"
printf 'algorithm,level,wall_seconds,user_seconds,sys_seconds,cpu,repo_bytes\n'

for item in "${cases[@]}"; do
  read -r algorithm level <<< "$item"

  repo="$BASE/${algorithm}-${level}"
  metrics="$repo.time"

  rm -rf "$repo" "$metrics"
  mkdir -p "$repo"

  common=(
    --stanza="$STANZA"
    --repo1-path="$repo"
    --log-level-console=warn
  )

  pgbackrest "${common[@]}" stanza-create

  /usr/bin/time \
    -f '%e,%U,%S,%P' \
    -o "$metrics" \
    pgbackrest "${common[@]}" \
      --type=full \
      --archive-check=n \
      --compress-type="$algorithm" \
      --compress-level="$level" \
      backup

  repo_bytes=$(du -sb "$repo" | awk '{print $1}')
  printf '%s,%s,%s,%s\n' \
    "$algorithm" "$level" "$(cat "$metrics")" "$repo_bytes"
done

例如保存为 bench-pgbackrest.sh 后,在已经配置好 pgBackRest 的测试数据库上运行:

chmod +x bench-pgbackrest.sh
sudo -u postgres ./bench-pgbackrest.sh | tee compression-results.csv

单轮测试容易受到页面缓存、后台任务和存储抖动影响。更可靠的做法是:

  1. 每个组合至少运行三次;
  2. 轮换或随机化测试顺序,避免后运行的任务持续受益于缓存;
  3. 所有组合保持相同的 process-max、数据库快照和存储路径类型;
  4. 同时观察数据库业务延迟,而不只是备份进程的完成时间;
  5. 用正式 WAL 归档配置再做一次真实恢复测试。

如何从结果中选择参数

zst(3) 作为基线,分别计算其他组合相对它节省了多少空间,又增加了多少时间和 CPU。决策时可以使用一个简单问题:

为了再减少 1 GB 仓库占用,需要额外付出多少 CPU 秒和多少备份时间?

如果 zst(6) 只让仓库略微缩小,却明显延长备份窗口,那么应保留 zst(3)。如果网络带宽或对象存储容量才是主要成本,并且主机有充足的空闲 CPU,更高级别才可能有意义。

上线前可以按下面的清单确认:

  • 默认从 compress-type=zstcompress-level=3 开始;
  • 在代表性数据上比较空间、耗时和 CPU,而不是使用空库测试;
  • 调整压缩级别时保持并行度不变;
  • 在业务高峰期观察数据库延迟和 CPU steal、iowait;
  • 同时验证全量、差异和增量备份;
  • 完成一次端到端恢复,并记录恢复耗时;
  • 只有在空间或网络收益足够明确时,才提高压缩级别。

压缩参数的目标不是制造最小的备份文件,而是构建一条能长期稳定运行、可以按时恢复、并且不会拖慢数据库的备份链路。对多数环境而言,从 pgBackRest 默认的 zst(3) 开始测量,比直接追逐最高压缩率更稳妥。


相关推荐