30.5 升级前检查与业务验证
升级会复制或重新解释现有状态。源端已经存在的 invalid index、prepared transaction、 catalog 漂移或数据损坏,不会因为换了 major 自动痊愈;它们只会让故障因果更加难分。
升级前检查的目标不是证明数据库“完美”,而是建立一个已知、可恢复、可比较的起点。
30.5.1 系统目录、无效对象与长事务
第一组:cluster 与 database inventory
SELECT datname,
pg_encoding_to_char(encoding) AS encoding,
datlocprovider,
datcollate,
datctype,
datlocale,
datcollversion,
datallowconn
FROM pg_database
ORDER BY datname;
SELECT spcname, pg_tablespace_location(oid)
FROM pg_tablespace
ORDER BY spcname;
SELECT rolname, rolsuper, rolreplication, rolbypassrls
FROM pg_roles
ORDER BY rolname;随后逐 database 采集 extension、collation、schema、owner、privilege、large object、
publication/subscription、FDW/server/user mapping、database/role settings。pg_upgrade
处理的是整个 cluster,漏掉一个平时不连接的 database,也可能在 schema dump/restore
阶段让全局升级失败。
第二组:不完整与待完成状态
SELECT i.indexrelid::regclass AS index_name,
i.indisready,
i.indisvalid,
i.indislive
FROM pg_index AS i
WHERE NOT i.indisready
OR NOT i.indisvalid
OR NOT i.indislive
ORDER BY 1;
SELECT conrelid::regclass AS relation,
conname,
contype,
convalidated
FROM pg_constraint
WHERE NOT convalidated
ORDER BY 1, 2;
SELECT transaction, gid, prepared, owner, database
FROM pg_prepared_xacts
ORDER BY prepared;invalid index 可能来自失败的 CREATE INDEX CONCURRENTLY;它是否删除、重建或保留,
要在升级前决定。NOT VALID constraint 可以是有意的渐进变更,但必须进入 inventory。
prepared transaction 是未完成的分布式业务事实,不能在停机时当普通长连接粗暴清掉。
还要检查 logical replication:
SELECT slot_name, slot_type, database, active,
restart_lsn, confirmed_flush_lsn,
wal_status, invalidation_reason
FROM pg_replication_slots
ORDER BY slot_name;
SELECT subname, subenabled, subslotname
FROM pg_subscription
ORDER BY subname;PG17+ 的某些 logical slot/subscription 状态可由 pg_upgrade 迁移,但必须满足官方升级
前提;老版本、无效 slot 和复杂拓扑不能靠默认推断。
第三组:活动与变更冻结
SELECT pid, datname, usename, application_name,
state, xact_start, backend_xid, backend_xmin,
wait_event_type, wait_event
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start;正式停机前应:
冻结 DDL 与 extension 变更
停止 scheduler / ETL / schema migrator
drain application writers and long transactions
resolve prepared transactions by their coordinator
ensure replicas caught up
record final configuration and object manifest
stop old primary cleanlypg_upgrade --check 还会检查 version、control data、prepared transaction、部分不支持
类型、required libraries、logical slot/subscription 等条件。它是必要门禁,但不覆盖
应用查询与业务不变量。
一个容易遗漏的原生限制是:pg_upgrade 不支持用户列使用若干保存 OID 的 reg*
类型,如 regcollation、regconfig、regproc、regprocedure;regclass、
regrole、regtype 可升级。preflight 应按目标版本文档扫描,而不是等正式窗口报错。
30.5.2 amcheck、checksum 状态与备份恢复证据
在线先做结构检查
对已选重要 B-tree:
CREATE EXTENSION IF NOT EXISTS amcheck;
SELECT bt_index_check(
index => i.indexrelid,
heapallindexed => i.indisunique,
checkunique => i.indisunique
)
FROM pg_index AS i
WHERE i.indexrelid IN (
'app.orders_pkey'::regclass,
'app.orders_order_code_key'::regclass
);bt_index_check 用与实际 index scan 相同的 operator class/comparison 逻辑验证 B-tree
结构与顺序;启用 heapallindexed 还会检查 heap tuple 是否有对应 index tuple。更强的
bt_index_parent_check 检查 parent/child invariant,但锁与成本更高。
大库不能在窗口前临时对所有 index 做最重检查。按:
系统目录和关键唯一索引
近期报错/存储异常对象
最大与最热对象
抽样普通对象分层,并在生产克隆中测量耗时。失败时先转入第 35 章的数据抢救流程,不要把损坏对象 直接送进升级。
停库后再做全 cluster checksum 检查
pg_checksums --check --progress -D /pg/data/17pg_checksums 要求 server clean shutdown;check 会扫描 cluster 文件,发现至少一个
checksum failure 时返回非零。启用/禁用 checksum 更是会修改数据块或 control file,
HA 拓扑必须所有节点一致处理,不能把它顺手塞进 major upgrade。
PostgreSQL 18 initdb 默认开启 checksums,而 pg_upgrade 要求 old/new 设置匹配。
本章实验显式构造:
old PG17 checksums on
new PG18 checksums off--check 返回 1;runner 删除这个不兼容的目标,重新以 checksums on 初始化,才允许
继续。
“有备份”必须变成一次可恢复证据
升级票据至少绑定:
backup_id: ...
source_system_identifier: ...
start_lsn: ...
stop_lsn: ...
timeline: ...
manifest_verified: true
required_wal_present: true
restore_target: isolated-pg17
restore_completed_at: ...
logical_manifest_equal: true
rto_measured: ...pg_verifybackup 可以按 backup manifest 检查文件、摘要和所需 WAL,但官方明确说明它
不能覆盖启动 server 时的全部检查,仍需 test restore。Pigsty/pgBackRest 的
check、backup info 和 repository 健康也不能替代实际恢复。
回退到旧 cluster 依赖旧版本的可恢复性,所以升级前的 restore 应首先恢复为 old major。 升级后还要建立 new major 的新备份基线,并再次恢复;不能无限依赖切换前那份旧版本 备份。
30.5.3 查询结果、计划、性能和业务不变量基线
先比较结果,再讨论计划
一个新 major 选择了不同 plan,不一定是回归;选择了同一 plan,也不证明结果正确。 验证顺序:
- error/SQLSTATE 与行结果;
- 行数、排序、NULL、类型与精度;
- 业务不变量;
- plan shape、估算与实际行数;
- latency、吞吐、CPU、I/O、WAL 与锁。
从 pg_stat_statements、APM 和业务清单建立代表性 query corpus:
top total time
top mean/p99 latency
top calls
largest temp/WAL/I/O
关键交易与结算
低频但高风险管理语句
DDL / migration / backup / exporter queries参数分布很重要。只用一个平均 customer_id 做 EXPLAIN,无法发现 skew、NULL、热点和
极端时间范围。
保存可比的证据格式
EXPLAIN (
ANALYZE,
BUFFERS,
WAL,
SETTINGS,
VERBOSE,
FORMAT JSON
)
SELECT ...;对写 SQL 应在可回滚、隔离的克隆上执行。记录:
server version and system identifier
schema/data snapshot identity
session GUC
parameter values or distribution class
cold/warm cache condition
concurrency
plan JSON
result digest
latency distribution and resource counters不要逐字比较 cost;新版本 cost model、节点和统计可能合理变化。设置门禁:
result: exact
business_invariants: zero violations
p95_latency: <= old * 1.15
p99_latency: <= old * 1.25
error_rate: no regression
temp_bytes: <= budget
wal_bytes_for_write_corpus: <= budget
plan_regression: reviewed, not byte-identical本章 fixture 查询 order_code = 'order-5000' 在 PG17 和 PG18 都返回同一行,两个版本
都使用 orders_order_code_key Index Scan。实验记录完整 plan JSON,但 validator 只强制
业务结果相等和 plan 存在,不把“必须同一个节点”误写成普遍升级合同。
业务不变量是最终解释层
通用数据摘要之外,还应验证:
账务借贷平衡
订单状态合法且转移可达
租户间无交叉
外键孤儿为零
sequence next value 安全
任务水位和队列 offset 一致
权限矩阵不扩大
collation-sensitive pagination 稳定这些规则应在 old snapshot 和 upgraded snapshot 上运行相同版本,并保存异常主键范围。 否则应用测试只能告诉你几个请求成功,不能证明整批数据仍满足业务语义。
30.5.4 amcheck 与 checksum 检测对象不同
| 证据 | 主要检测 | 不能证明 |
|---|---|---|
| page checksum | page 从写入后是否发生可检测的物理变化 | SQL 逻辑、所有内存/写入前错误、索引业务一致性 |
pg_checksums --check | clean-shutdown cluster 中 checksum page 扫描 | 未启用 checksum 的历史、server 可恢复、业务正确 |
amcheck B-tree | page/link/order、可选 heap/index coverage 与 uniqueness | 所有 access method、业务行值、底层每个文件摘要 |
verify_heapam | heap 结构异常并尽量继续报告 | 所有 index、备份可恢复 |
| backup manifest verify | 备份文件、摘要、所需 WAL 的一部分完整性 | server 启动和业务恢复 |
| test restore | 备份能在声明环境恢复并启动 | 之后每笔新写、全部应用语义 |
| logical manifest | 行级规范化结果和业务聚合 | 物理 page/index 结构 |
它们不是相互替代关系:
checksums pass + amcheck fails
-> page 未被随机篡改,但 index 逻辑结构可能不满足 invariant
amcheck passes + checksum fails elsewhere
-> 已检对象逻辑可读,但其他 page 物理完整性有问题
both pass + restore fails
-> backup/WAL/config/secret/extension 链仍可能不完整
all pass + business invariant fails
-> 数据在物理和结构层可读,业务事实仍然错误升级发布至少需要这四条独立证据线:
physical integrity
structural integrity
recoverability
logical/business equivalence把它们压成一个“数据库健康检查已通过”复选框,会丢掉每项证据真正覆盖的边界。
上一节:locale、collation 与索引风险 · 返回本章目录 · 下一节:用隔离环境完成升级彩排 · 查看全书目录 · 查看索引中心