PostgreSQL data_checksums:一个只读 GUC 背后十三年的数据完整性故事

2026-06-05 15 预计阅读时间:1 分钟
来源:postgr.es AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:7 分钟

在 PostgreSQL 里,SHOW data_checksums 只会返回 onoff——和 block_size 一样,它是个只读的预设参数,初始化集群时就定了,之后无法通过 ALTER SYSTEM 修改。但这个看似平淡的开关,背后是一场持续了十三年、至今仍在演进的数据完整性战役。

页面校验和到底在查什么

PostgreSQL 的数据文件由一个个固定大小的页面(默认 8KB)组成。每次读写页面时,操作系统和硬件并不保证内容完好——磁盘静默损坏、内存位翻转、内核 bug 都可能让一个页面悄悄变质,而数据库直到下次真正解析该页面时才会发现异常,甚至可能永远发现不了。

data_checksums = on 后,每个页面写入磁盘前都会计算一个校验和并写入页面头部;读取时重新计算并比对。一旦不匹配,PostgreSQL 立刻报错,而不是让损坏数据静默传播。

查看当前集群状态,最直接的方式:

-- 在 psql 中执行
SHOW data_checksums;

返回 onoff。你也可以用底层工具确认:

pg_controldata /var/lib/postgresql/16/main | grep checksum

输出类似:

Data page checksum version:           1

版本号为 1 表示校验和已启用,0 表示关闭。

十三年的曲折历程

校验和的故事从 2013 年 PostgreSQL 9.3 开始——这是第一个支持 initdb --data-checksums 的版本。但当时的设计有一个硬限制:只能在初始化时开启,已有集群无法追加启用。大量生产库已经跑起来了,想加校验和只能逻辑导出再导入,代价极高。

社区花了多年时间解决这个问题。关键里程碑:

  • 9.3initdb 时可选开启,一旦开启不可关闭。
  • 11:引入 pg_checksums 命令行工具,可以在停机状态下对已有集群启用或禁用校验和,不再需要重初始化。
  • 12+:逐步优化校验和算法的性能开销,社区持续讨论是否提供在线启用(不停机)的能力。

至今,在线启用校验和仍是未完全落地的功能——这正是 Christophe Pettus 所说"历史仍在书写"的部分。

用 pg_checksums 给现有集群启用校验和

如果你的集群是 11 或更高版本,且当前 data_checksums = off,可以在停机窗口内用 pg_checksums 一次性启用:

# 1. 先确认当前状态
pg_checksums -c /var/lib/postgresql/16/main
# 输出: Checksums are disabled in cluster "/var/lib/postgresql/16/main"

# 2. 停库
pg_ctl -D /var/lib/postgresql/16/main stop -m fast

# 3. 启用校验和(-e 表示 enable,-P 显示进度)
pg_checksums -e -P /var/lib/postgresql/16/main
# 输出进度条,扫描并写入所有文件的校验和

# 4. 确认结果
pg_checksums -c /var/lib/postgresql/16/main
# 输出: Checksums are enabled in cluster ...

# 5. 启库
pg_ctl -D /var/lib/postgresql/16/main start

启用后,pg_stat_database 视图新增了 checksum_failures 列,可以实时监控校验失败次数:

SELECT datname, checksum_failures
FROM pg_stat_database
WHERE checksum_failures > 0;

一旦出现非零值,说明已经有页面在磁盘上损坏了——这是你原本可能永远不会察觉的问题。

性能开销与取舍

校验和不是免费的。每次页面写入要计算并存储校验和,每次读取要验证。社区基准测试显示,典型 OLTP 场景的性能下降在 1%–5% 之间,具体取决于写入频率和页面大小。对于以读为主的工作负载,影响更小。

几个值得注意的细节:

  • 全页写(full_page_writes)与校验和的关系:WAL 的全页写机制本身也会保护第一次修改后的页面,但校验和覆盖的是所有后续读取场景,两者互补而非替代。
  • 大页面(huge pages):使用 Linux huge pages 时,校验和同样生效,但内存位翻转的风险本身在 huge pages 上略高(因为管理粒度更大),启用校验和反而更有意义。
  • 复制场景:主库开启校验和后,备库在接收 WAL 并回放时也会验证页面校验和,损坏会在备库侧被检出。

什么时候该开启——一个决策清单

场景 建议
新建集群 直接 initdb --data-checksums,没有理由不开
现有生产库(PG ≥ 11) 在下一个计划停机窗口用 pg_checksums -e 启用
现有生产库(PG < 11) 升级到 11+ 后再启用,或通过逻辑迁移重建
对延迟极度敏感的 OLTP 先在测试环境跑基准,确认 1%–5% 的开销可接受
只读分析库 开启几乎没有负面影响,强烈建议启用

核心判断逻辑很简单:静默数据损坏是不可逆的灾难,而校验和的性能开销是可测量的、可控的。除非你的系统对每毫秒都不可妥协,否则开启校验和是更安全的默认选择。

最后一点:如果你已经在运行中发现了 checksum_failures > 0,不要慌,但不要拖延——这意味着磁盘或文件系统已经在丢失数据。立刻排查存储硬件,并从备份恢复受影响的数据库,而不是继续在损坏的页面上读写。


相关推荐