跳至内容

35.3 页与 checksum 证据

PostgreSQL data checksum 是发现部分静默字节变化的重要机制,但不是万能完整性证明。 理解其单位、触发时机和未覆盖面,才能正确解释一次成功或失败的检查。

35.3.1 checksum 是否启用及其检测边界

先确认,而不是假设

在线只读确认:

SHOW data_checksums;

SELECT data_page_checksum_version
FROM pg_control_init();

data checksum 是 cluster 级属性,不按 database/table 单独启用。启用时,每个 data page 在写入时更新 checksum,读取时校验。PostgreSQL 18 的默认 initdb 行为可能因工具与 选项而异,生产 inventory 必须保存实际值。

离线检查:

pg_checksums --check --pgdata=/exact/clone/pgdata

官方要求 PostgreSQL clean shutdown 后运行 pg_checksums。返回码为 0 表示本次 扫描没有 checksum error,非 0 表示至少检测到一次失败。不要只解析人类输出而忽略 exit status,也不要对正在运行或有其他 writer 的 PGDATA 执行。

如需限定已知 relation filenode,可用:

pg_checksums --check \
  --filenode=16395 \
  --pgdata=/exact/clone/pgdata

这适合复验定位,不替代 full-cluster scan。

覆盖与不覆盖

checksum 保护 data pages,但官方明确不覆盖:

  • internal data structures 的全部状态;
  • temporary files;
  • 业务语义与跨行不变量;
  • 是否遗漏了整个 relation/file;
  • collation/operator class 规则改变;
  • 被正确重写成错误内容的合法页面。

它也不是纠错码:能发现不一致,不能根据 checksum 自动恢复原字节。

读时检测的含义

在线读取坏页通常中止当前 transaction。若 page 仍在 shared buffer 且损坏发生在存储 副本上,何时重新从设备读会影响首次发现时间;因此“昨天没报错”不证明昨天设备上 没有坏块。离线全扫与经过业务访问的在线读覆盖不同。

ignore_checksum_failure=on 只会在报告 warning 后尝试继续;官方警告它可能导致 crash、传播或隐藏损坏。它不是高可用开关,本章实验保持 off。

35.3.2 日志、块号、关系文件与物理定位

从数据库 identity 映射到文件

对还可查询的 clone:

SELECT c.oid,
       n.nspname,
       c.relname,
       c.relkind,
       c.relfilenode,
       pg_relation_filenode(c.oid) AS current_filenode,
       pg_relation_filepath(c.oid) AS relative_path,
       pg_relation_size(c.oid) AS bytes
FROM pg_class AS c
JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE c.oid = 'public.target_table'::regclass;

使用 pg_relation_filenode/path,不要假设 OID 等于当前 filenode。TRUNCATE、REINDEX、 某些 ALTER/rewrites 会更换 filenode;tablespace 又改变相对路径。

PostgreSQL 默认 block size 常见为 8192,但应从实际 control data确认:

SELECT database_block_size
FROM pg_control_init();

日志块号 $b$ 对应 relation fork 内的字节范围:

$$ [b \times B,\ (b+1)\times B) $$

其中 $B$ 是实际 block size。这只是定位数学,不是授权用十六进制编辑器修改该范围。

先确定 fork 与 segment

大 relation 会分成 segment;relation 还有:

main fork
_fsm free space map
_vm visibility map
_init unlogged initialization fork
TOAST relation and indexes

错误路径、block 和 relation identity 一起保存。index 的 block 2 与 heap 的 block 2 不是同一数据;同名 relation 在不同 database/tablespace 也不同。

日志与 SQLSTATE

保留:

SQLSTATE
severity
relation/database/backend identity if available
block number and file path
statement/query_id with privacy controls
UTC and log sequence
preceding kernel/storage messages

本章正式 bit-flip case 的在线顺序扫描返回 XX001,但教材没有把 raw stderr 导出, 因为错误文本可能带 object/query 信息。生产证据可在受控位置保存完整原日志,再制作 去敏投影用于协作。

物理定位不等于根因定位

找到 base/5/16395 block 2 只说明错误出现在哪里。根因仍可能在:

memory / CPU
filesystem / volume / controller / drive
hypervisor / cloud storage
DMA / firmware
PostgreSQL or extension bug
offline operator action
backup/restore transfer

需要跨层证据,而不是仅替换这一文件。

35.3.3 存储故障先修基础设施,再谈数据库重建

不要把健康数据恢复到坏底座

如果设备仍报告 error、filesystem 不稳定、memory test 未过或 hypervisor path 不可信, 在原主机恢复 backup 可能再次损坏干净数据。安全路线:

fence suspect host/storage from authority
preserve device and filesystem evidence
provision verified clean failure domain
restore/reseed from verified source
validate before accepting traffic
keep suspect media isolated for analysis

RAID rebuild、filesystem repair、cloud volume detach/attach 都会改变现场,应由对应专业 团队纳入同一时间线。数据库团队不要在唯一卷上自行执行 fsck -y

健康底座的验收

hardware/controller/drive diagnostics
kernel error-free observation window
filesystem consistency and mount semantics
memory/CPU health
power and time synchronization
firmware/driver/package baseline
write durability assumptions
independent backup/restore test

“新 VM”也不自动独立:它可能仍使用相同宿主机、storage pool、image 或坏备份。

重建后仍要扫描

新副本需要:

clean PostgreSQL startup/recovery
pg_checksums on a clean-stopped clone or scheduled validation
amcheck by risk-ranked object set
business invariants and query equivalence
replication/archive/backup health
service role and endpoint identity
monitoring and alert observation window

若从 physical backup 恢复,损坏页可能被原样复制;“restore 成功”只说明工具完成传输。 第 21 章的 restore drill 要与本章的 integrity checks 组合。

本节结论

checksum error
  -> page evidence
  != root component
  != automatic data-loss estimate
  != permission to edit/delete

下一节处理 checksum 可能发现不了、却会让查询返回错误答案的派生结构。


上一节:先分类再抢救 · 返回本章目录 · 下一节:索引、collation 与 amcheck · 查看全书目录 · 查看索引中心

最后更新于