30.1 先识别变化类型
升级风险首先取决于“什么发生了变化”。同一个“版本升级”工单,可能只是在同一 major 里换修复版,也可能跨越 data directory、系统目录、SQL 行为和扩展 ABI。若不先分类, 团队很容易把 minor upgrade 做成一次不必要的数据迁移,或把 major upgrade 当成滚动 重启。
30.1.1 小版本、安全修复与大版本
版本号先按 PostgreSQL 规则读
从 PostgreSQL 10 开始:
17 -> major
17.10 -> major 17 的第 10 个 minor release
17 -> 18 -> major upgrade
17.9 -> 17.10 -> minor upgrade9.6 及更早版本使用前两段表示 major,例如 9.5→9.6 是 major upgrade, 9.6.23→9.6.24 才是 minor upgrade。不要用通用 SemVer 的 “major.minor.patch”直觉解释 PostgreSQL。
社区的版本策略给出两个硬边界:
- 每个 major 通常支持五年,超过 EOL 不再获得正常修复;
- 同一 major 的 minor release 不改变内部存储格式,官方建议运行当前 minor;
- major 会改变不向后兼容的 data directory,需要 dump/restore、
pg_upgrade或逻辑 迁移; - 可以跨多个 major 升级,但必须阅读所有跨越版本的 release notes。
分类表:
| 类型 | 数据目录 | 典型动作 | 仍需验证 |
|---|---|---|---|
| minor 修复 | 同 major 兼容 | 换二进制并重启 | release note、扩展包、HA 逐节点顺序 |
| 紧急安全修复 | 通常仍是 minor | 缩短审批与暴露时间 | CVE 触发面、临时缓解、升级后攻击面 |
| major | 不直接兼容 | 三类迁移路径之一 | 全部数据、行为、扩展、客户端和回退合同 |
| OS/libc/ICU 更新 | PG 版本可不变 | 系统维护 + 对象评估 | collation、TLS、动态库、驱动 |
| 扩展更新 | PG 版本可不变 | 包 + ALTER EXTENSION | update path、对象重建、不可降级 |
“安全修复”不是第四种存储格式;它是变更优先级。风险高的漏洞可能要求更快上线,但不能 免除备份、逐节点、兼容和回退检查。反过来,社区明确认为长期停留在旧 minor 往往比及时 升级风险更大。
Pigsty 中的 minor rolling 仍有顺序
同一 major 的 HA 集群通常可以:
准备并锁定同一套 minor/extension 包
-> 升级 replicas
-> 分别重启并等待重新追平
-> switchover
-> 升级原 primary
-> 重启、追平、验收Pigsty 提供包仓、Ansible、Patroni 与 pg 管理命令来执行这条链,但“rolling”不等于
所有节点同时更新。每一步都应确认:
SELECT version(), pg_is_in_recovery();并观察 replica replay、slot、客户端错误与业务 SLO。扩展 .so 必须与每个节点正在
运行的 server binary 匹配;只升级 primary 的扩展包,下一次 failover 可能把故障推给
replica。
major 不能靠“replica 先装 18、primary 仍跑 17”完成物理滚动升级。物理流复制要求同一 major;跨 major 需要逻辑复制或重建后的拓扑。
30.1.2 SQL 行为、系统目录、参数和默认值
release notes 要转成可执行差异
不要只读“新特性亮点”。major release notes 的 migration/incompatibilities 部分才是 升级清单的起点。以 17→18 为例,变化包括但不限于:
initdb默认启用 data checksums;pg_upgrade开始保留大部分优化器统计,但 extended/custom/cumulative statistics 仍不完整;- generated column 默认形态、时区缩写解析、
VACUUM/ANALYZE对继承子表的行为变化; - 旧
psql对 PostgreSQL 18 的某些 CSV\copy边界可能不兼容; - 某些系统视图列或含义发生变化;
- 默认 collation provider 相关行为会影响全文检索与
pg_trgm索引。
本章实验正是利用第一条真实边界:源 PG17 启用了 checksums,而一个用
--no-data-checksums 初始化的 PG18 目标被 pg_upgrade --check 拒绝:
old cluster uses data checksums but the new one does not这说明“新版本的默认值更安全”不能替代显式匹配。目标必须按源集群和新架构的合同 初始化。
四张差异表
升级 ADR 至少维护:
| 表 | 典型内容 | 证据 |
|---|---|---|
| removed/changed behavior | SQL、类型、权限、触发器、排序、错误码 | release notes + query corpus |
| parameter diff | 删除、重命名、默认值、单位、context | pg_settings、新旧配置渲染 |
| catalog diff | 列、view、enum/code、权限 | exporter/脚本 SQL 的兼容测试 |
| reserved words/API | parser、函数签名、客户端协议 | schema restore + driver test |
在旧环境导出当前设置时,不要只保存一个手工编辑过的 postgresql.conf:
SELECT name,
setting,
unit,
source,
sourcefile,
sourceline,
pending_restart
FROM pg_settings
ORDER BY name;
SELECT sourcefile,
sourceline,
seqno,
name,
setting,
applied,
error
FROM pg_file_settings
ORDER BY seqno;第一张是最终有效值,第二张是配置文件解析结果。两者配合才能发现:
同名参数被后续 include 覆盖
新版本已不认识旧参数
配置行语法错误
值已写入但需要 restart
环境变量 / ALTER SYSTEM / 命令行改变来源同样地,HBA 要用 pg_hba_file_rules 解析,不能只做文本 diff。
系统目录不是跨 major 的稳定应用 API
监控、迁移脚本和内部工具经常直接读取 pg_stat_*、pg_catalog。这些是 PostgreSQL
公开能力,但列集合和含义可以随 major 演进。避免:
SELECT * 后按列位置解码
假设枚举状态永远只有旧值
把 OID 当跨集群稳定标识
在 SQL 中硬编码 server 版本分支却不测试应显式列名,并以 server_version_num 选择经过测试的查询:
SELECT current_setting('server_version_num')::int;升级前在新版本空集群上先跑完整 exporter、备份、健康检查和自动化 SQL。目标不是 “SQL 不报错”而是输出字段、单位和告警语义仍正确。
30.1.3 驱动、连接池、备份与观察组件兼容
兼容矩阵的单位是“实际组合”
不要写“JDBC 支持 PostgreSQL”。应记录:
application: checkout-v4
runtime: Java 21
driver: pgjdbc x.y.z
pool: HikariCP x.y.z
proxy: PgBouncer x.y
old_server: PostgreSQL 17
new_server: PostgreSQL 18
auth: scram-sha-256 + TLS verify-full
session_features:
- prepared statements
- binary transfer
- application_name
- statement_timeout
tested_queries: checkout-corpus-v8驱动测试至少覆盖:
- 认证、TLS、channel binding、证书和密码轮换;
- 参数类型推断、binary/text 编解码、timestamp、numeric、array、JSON、large object;
- server-side prepare、statement cache、batch、COPY;
- error SQLSTATE、generated keys、cancel、timeout;
- failover、连接重建、transaction status 和 read-only 标志。
PgBouncer/连接池还要覆盖 session state。升级切换时保留的旧连接不会自动变成新版本
连接;prepared statement、临时表、SET、advisory lock 和 transaction pooling 的语义
需要按实际模式测试。发布证据必须包含“新建连接看到目标 system identifier”,而不只
看 pool 端口可达。
备份工具要同时验证生产与恢复端
逻辑迁移通常应使用目标版本的 pg_dump 读取旧 server。官方说明:新版
pg_dump 可以读取受支持的旧 server,且输出面向相同或更高 server;旧版 pg_dump
会拒绝读取更高 major,dump 输出也不保证能恢复到更低 major。
这带来几条门禁:
new pg_dump -> old source must pass
new pg_restore -> new target must pass
backup agent -> old during window must pass
backup agent -> new after cutover must pass
restore tooling -> isolated new cluster must pass物理备份则与 server major、WAL、control file 和工具版本绑定。不能把 PG17 的物理备份 直接恢复成 PG18;它应先恢复为 PG17,再走获批的升级路径。Pigsty 中 pgBackRest 配置、 repository、stanza、retention 和恢复脚本都要在新拓扑重验,而不是只确认最新 backup 状态是 completed。
“监控没报警”可能是 exporter 已失明
升级后指标归零有两种解释:
系统没有负载
采集 SQL 已失败或字段含义改变因此观察组件要做三向核对:
| 组件 | 新版本检查 | 原生对照 |
|---|---|---|
| exporter | scrape success、query errors、字段数 | pg_stat_* 原始 SQL |
| Grafana/Pigsty 面板 | 时间序列连续、label 未漂移 | server identity 与真实 workload |
| log pipeline | 新错误格式、severity、采集延迟 | PostgreSQL 本地 log |
| alert rule | 正例能触发、恢复能关闭 | 人工受控 canary |
升级测试应主动产生一条查询、一个可识别错误和一小段 WAL,确认应用、日志、指标和告警 四条链都看到同一时间线。只有全部组件对新 major 给出有意义的数据,才叫“观察能力 兼容”。
返回本章目录 · 下一节:三类大版本升级路径 · 查看全书目录 · 查看索引中心