18.6 实战:设计 `pg36_shop` 生产蓝图
第 18 章实战与前几章不同:
no setup
no DDL
no DML
no reset
no service deployment它把现有证据读出来,检查蓝图是否有资格进入下卷。风险等级是 L0。
18.6.1 选择保留在 PostgreSQL 内的能力
前置状态
实验要求第 4、13–17 章的最终 fixture 保留在同一本地开发实例:
database=pg36_shop
PostgreSQL major=18
session_user=postgres
pg36_owner=NOLOGIN non-superuser
pg36_app=LOGIN non-superuser
ch04-v1 physical model
ch13 routine guard
ch14 extension lifecycle
ch15 search quality
ch16 spatiotemporal
ch17 analytics/FDW + two shard database shells缺失时本章直接失败,返回前章重建;它不会悄悄修复。
私有连接
沿用:
[pg36-admin]
host=/path/to/socket-or-host
port=5432
dbname=pg36_shop
user=postgreschmod 600 /path/to/pg_service.conf
export PGSERVICEFILE=/path/to/pg_service.conf
export PGSERVICE=pg36-admin密码或其他 secret 放在批准的连接机制中,不放命令行、脚本、evidence 或 Git。
先读实验合同
lab-contract.md
规定:
risk=L0 read-only
target=confirmed local fixture
allowed=catalog reads + JSON validation + evidence files
forbidden=DDL/DML/roles/extensions/deploy/failover/backup/reset
pigsty_l1=not-run本章脚本没有 setup/reset action。这不是遗漏,而是用接口形状表达安全
边界。
上卷前置复核
task.sh 依次调用:
static/labs/ch04/task.sh verify
static/labs/ch13/task.sh verify
static/labs/ch14/task.sh verify
static/labs/ch15/task.sh verify
static/labs/ch16/task.sh verify
static/labs/ch17/task.sh verify它们只验证 retained fixture。第 17 章还分别连接 pg36_shard_a 和
pg36_shard_b,防止协调端看似正常而远端状态已经漂移。
只读事务
每个 catalog capture 都显式开始:
BEGIN TRANSACTION
ISOLATION LEVEL REPEATABLE READ
READ ONLY;再 include
context.sql。
context 验证:
current_database = pg36_shop
server_version_num in 18.x
session_user = postgres superuser
can inspect pg36_owner
owner role = NOLOGIN, non-superuser
app role = LOGIN, non-superuser
ch04 schema_version present脚本结束 COMMIT,但 read-only 事务没有业务变更。
平台状态
platform-state.sql
输出稳定 key/value:
database=pg36_shop
server_major=18
server_version=18.4 (formal run)
session_user=postgres
in_recovery=false
model_version=ch04-v1
relation_checksum=f8a7bfae59c6d16cd323abecfefe1014
pigsty_reference=4.4
pigsty_l1=not-run
mutation=nonemutation=none 不是只靠自报:all 在前置复核后抓两轮,并对状态与 catalog
逐字节 cmp。
能力快照
capability-snapshot.sql
把数据库事实压成九行:
| capability | lifecycle | evidence |
|---|---|---|
| relational core | accepted | ch04-v1 |
| atomic database logic | accepted with scope | ch13-routine-guard-v1 |
| lexical/fuzzy search | accepted | pg_trgm:1.6 |
| semantic search | pilot | vector:0.8.4 |
| spatiotemporal | conditional | btree_gist:1.8,postgis:3.6.4 |
| analytical federation | lab-only | postgres_fdw:1.2 |
| search quality fixture | accepted | ch15-search-v1 |
| spatiotemporal fixture | accepted | ch16-spatiotemporal-v1 |
| analytics fixture | accepted | ch17-analytics-v1 |
这里有意把“扩展安装事实”和“生命周期判断”并列。SQL 能证明版本存在, 生命周期还来自前章的质量、安全与运维边界。
extension catalog
extension_name
extension_version
schema_name
owner_name
relocatable
comment正式 fixture 精确包含六项:
btree_gist 1.8
pg_trgm 1.6
plpgsql 1.0
postgis 3.6.4
postgres_fdw 1.2
vector 0.8.4教学扩展必须保留 pg36 chXX ... safe to rebuild marker。marker 只用于本书
精确识别,不应照搬成生产对象治理方案。
schema 与 role catalog
shop / shop_private
shop_ch13 / shop_ch14 / shop_ch15
shop_ch16 / shop_ch16_ext
shop_ch17 / shop_ch17_ext每项必须由 pg36_owner 拥有并保留精确 comment。
role-catalog.sql
只导出三种相关身份,避免把环境中其他角色误收入出版 fixture。审查器验证:
pg36_app LOGIN, !SUPERUSER, !BYPASSRLS
pg36_owner NOLOGIN, !SUPERUSER
postgres LOGIN, SUPERUSER (formal local admin)为什么不探测 Pigsty
当前实例不是本章声明的目标 Pigsty cluster。若脚本从本机进程名或目录猜测 Pigsty 状态,会产生伪证据。
所以蓝图准确写:
Pigsty reference mapping = documented
Pigsty L1 = not-run第 19 章在明确 target/inventory 后才执行环境验收。
18.6.2 选择外置组件及其数据契约
五份合同先于产品选型
external-data-contracts.json
包含:
product-cache-v1
order-events-v1
product-media-v1
analytics-export-v1
external-search-projection-v1每份必须有 17 个核心字段,包括:
id / kind / status / owner / authority
source / sink / freshness / delivery / ordering
idempotency / rebuild / failure_mode / reconciliation
deletion / security / exit这比简单画一条箭头严格得多。
cache 合同
关键规则:
business authority=PostgreSQL
cache identity=product_id + source version
TTL <= 300 seconds proposal
stale version never replaces newer
outage falls back to bounded PostgreSQL reads
namespace can be discarded and rebuiltvalidator 专门扫描 cache authority。若把:
"product_business_state": "cache"则报:
E_CACHE_AUTHORITYorder event 合同
business state + publication intent -> PostgreSQL transaction
delivery/replay log -> event bus
delivery -> at-least-once
ordering -> per order_id, no global order
idempotency -> stable event_idpublish lag 仍是 chapter 24 pending。写出 pending 比伪造一个 P99 更准确。
media 合同
bytes -> object storage
identity/owner/state/checksum -> PostgreSQL
immutable object version
visible only after checksum + metadata agree
orphan upload quarantined
two-phase deletion它是 accepted-boundary,表示“字节外置”这一边界已选择,不表示具体 object
provider 已选择或 L1 已通过。
analytics 合同
source=snapshot or CDC
sink=versioned immutable analytical tables
watermark on every dataset
last complete state
row/aggregate/partition checksum
tombstone propagation
new generation rebuild这份合同会在第 29 章的数据迁移与 CDC 状态机中具体化。
external search 合同
状态:
deferred-until-trigger进入条件不是“想用”,而是 PostgreSQL 搜索基线在质量、规模、语言或独立 SLO 上失败。
启用前必须证明:
snapshot + idempotent changes
monotonic product version/tombstone
index generation
quality golden
document count/payload hash
alias swap
fallback classification
exit to PostgreSQL正向文档关系
baseline-v1.6-proposal.json
引用所有合同。每项 capability 又引用它需要的合同。
validator 检查:
blueprint contract set == declared contract set
capability references exist
external/pilot/conditional placement has trigger
every capability has owner and evidence这能发现拼写、遗漏和结构漂移。
七个对抗性反例
negative-cases.json
不是伪造七份静态错误文件,而是对正确文档做 JSON path mutation:
| 反例 | 期望错误 |
|---|---|
| 无 evidence 宣称 Pigsty L1 passed | E_L1_EVIDENCE |
| 清空全部 exit path | E_EXIT_PATH |
| cache 成为商品业务权威 | E_CACHE_AUTHORITY |
| 删除消息合同 rebuild | E_CONTRACT_FIELD |
| loopback FDW 允许生产 | E_FDW_LAB_ONLY |
| 删除 production offering objective | E_SERVICE_OBJECTIVE |
| 删除 vector pilot gate | E_EXTENSION_GATE |
测试要求实际错误码与期望码精确相同。若错误文档意外通过,或被另一个更早的 无关规则拦截,negative suite 都失败。
为什么 validator 只用 Python 标准库
validate.py
只依赖:
argparse
copy
hashlib
json
pathlib目的不是排斥 schema 工具,而是让读者在最小环境中运行并看到业务策略代码。 生产平台可以再加 JSON Schema、OPA、CI policy 或签名。
canonical hash
报告为四份核心文档计算 canonical JSON SHA-256:
sort object keys
compact separators
UTF-8
preserve array order这避免 indentation/key order 影响内容身份,同时让 gate/capability 顺序仍然 有意义。
注意:canonical hash 证明文档未变,不证明内容正确;内容正确还靠人工决策、 数据库证据和负例。
18.6.3 输出服务目录草案、架构 ADR 与下卷验收问题
资产目录
static/labs/ch18/
├── lab-contract.md
├── architecture-adr.md
├── platform-map.mmd
├── pigsty-declaration.example.yml
├── service-catalog.json
├── external-data-contracts.json
├── baseline-v1.6-proposal.json
├── lower-volume-gates.json
├── negative-cases.json
├── context.sql
├── platform-state.sql
├── extension-catalog.sql
├── schema-catalog.sql
├── role-catalog.sql
├── capability-snapshot.sql
├── validate.py
├── review.py
└── task.sh没有生成的 evidence 被提交到源码目录。
单独验证文档
python3 static/labs/ch18/validate.py \
--blueprint static/labs/ch18/baseline-v1.6-proposal.json \
--catalog static/labs/ch18/service-catalog.json \
--contracts static/labs/ch18/external-data-contracts.json \
--gates static/labs/ch18/lower-volume-gates.json预期:
{
"status": "ok",
"counts": {
"offerings": 4,
"extension_bundles": 5,
"contracts": 5,
"capabilities": 9,
"lower_volume_gates": 18,
"exit_paths": 5
}
}加负例:
python3 static/labs/ch18/validate.py \
--blueprint static/labs/ch18/baseline-v1.6-proposal.json \
--catalog static/labs/ch18/service-catalog.json \
--contracts static/labs/ch18/external-data-contracts.json \
--gates static/labs/ch18/lower-volume-gates.json \
--negative-cases static/labs/ch18/negative-cases.json预期 case_count=7 且全部 actual/expected code 相等。
单轮 capture
evidence="$(mktemp -d /tmp/pg36-ch18.XXXXXX)"
PG36_EVIDENCE_DIR="$evidence" \
static/labs/ch18/task.sh capture输出:
status=capture-ok
mutation=none
evidence=/tmp/...每个 cycle 的
review.py
验证:
- manifest target/version/hash;
- relation checksum;
- extension/schema/role exact identity;
- capability lifecycle;
- normal/negative policy report;
- stderr 为空。
两轮正式运行
evidence="$(mktemp -d /tmp/pg36-ch18-final.XXXXXX)"
PG36_EVIDENCE_DIR="$evidence" \
static/labs/ch18/task.sh all正式 PostgreSQL 18.4 开发 fixture 的结果:
status=ok
preflight=ch04+ch13+ch14+ch15+ch16+ch17
cycles=2-byte-identical
documents=catalog+contracts+blueprint+18-pending-gates
counterexamples=7-rejected
pigsty_l1=not-run
mutation=none
release_candidate_checksum=beec6b6d47075a7b3b4a6aa6ee3ca2902ef8d555547fe6c2b2b009e56c25c9eb源码后续改变时 checksum 会改变;应以当次 manifest 与 validator report 为准。
两轮比较什么
platform-state.csv
extension-catalog.csv
schema-catalog.csv
role-catalog.csv
capability-snapshot.csv
validation-report.json
negative-report.json
review.txtmanifest.txt 含 capture 时间,故不做 byte compare;其余确定性证据必须一致。
运行后状态不需要复位
本章没有数据库写操作。若运行前后出现状态变化,应当视为:
- 外部并发变更;
- 某个前置 verify 实现违反只读预期;
- capture SQL/任务脚本缺陷;
- 环境不再适合作为冻结 fixture。
不要用 reset 掩盖,应先保留 evidence 并诊断。
架构 ADR
context
decision per capability
external contracts
service offerings
Pigsty reference mapping
proposed topology
positive consequences
costs/risks
rejected alternatives
revision triggers明确拒绝:
everything in PostgreSQL
everything split immediately
loopback FDW as production proof
Pigsty install as production readinessADR 的 status 是:
proposed; accepted for lower-volume validation,
not production approval18 个下卷 gate
lower-volume-gates.json
严格映射第 19–36 章:
| 章 | gate |
|---|---|
| 19 | deployment baseline |
| 20 | HA |
| 21 | backup/restore |
| 22 | access/routing |
| 23 | security |
| 24 | governance |
| 25 | observability |
| 26 | capacity |
| 27 | tuning |
| 28 | vacuum/maintenance |
| 29 | migration |
| 30 | upgrade |
| 31 | incident framework |
| 32 | PITR |
| 33 | failover/rebuild |
| 34 | overload |
| 35 | forensics |
| 36 | postmortem/platform improvement |
每个 gate 有 owner、两个核心问题、required evidence 与 pending 状态。
gate 不是章节阅读打卡
chapter completed 不等于 gate passed。例如读完第 21 章但没有在目标环境
恢复,ch21-backup-restore 仍然 pending。
通过 gate 应产生:
target identity
version
procedure
raw evidence
review result
owner approval
limitations
expiry/review trigger服务目录如何升级
下卷完成后,不直接覆盖 1.6-proposal。应:
- 收集每个 gate evidence;
- 修改不成立的 topology/objective/bundle;
- 记录 ADR revision;
- 生成新的 catalog/blueprint release;
- 重新跑正负 policy;
- 由 owner 批准;
- 保留 proposal 历史。
本章通过后能说什么
可以说:
在 PostgreSQL 18.4 的受控本地 fixture 上,第 4、13–17 章证据仍然成立;
pg36_shop的服务目录、能力决策、五份外置合同和 18 个下卷 gate 引用闭合, 七个危险反例被拒绝,两次只读快照一致。
不能说:
Pigsty 生产 cluster 已部署、SLO 已实现、备份可恢复、HA 可达目标、安全已 通过、容量足够。
这条语言边界,也是本章最后一项验收。
进入下卷
上卷回答:
PostgreSQL 如何正确建模、查询、扩展与交付应用能力下卷开始回答:
这些能力如何在真实环境中持续、可恢复、可观察、可升级地成为服务下一步是 第 19 章:环境规划与部署基线: 把 proposal 中的主机、软件、网络、存储、故障域和 Pigsty inventory 变成第一 份目标环境证据。
上一节:Pigsty 作为参考实现 · 返回本章目录 · 下一章:开天辟地:环境规划与部署基线 · 查看全书目录 · 查看索引中心