跳至内容
14.6 建立可复用扩展 ADR

14.6 建立可复用扩展 ADR

ADR(Architecture Decision Record)不是会议纪要,也不是给既定选择补理由。 它要让未来的维护者回答:

当时解决什么问题?
在什么版本和假设下?
比较了哪些替代?
什么证据使结论成立?
哪些风险仍然存在?
何时必须复审或退出?

本章提供 扩展 ADR 模板。模板不是为了 填满十个标题,而是强迫“价值—运行—退出”形成闭环。

14.6.1 问题、候选、假设与成功标准

标题写问题,不先写扩展

较差:

ADR-023: Adopt pgvector

更好:

ADR-023: Semantic nearest-neighbor retrieval for product support corpus

第二种标题允许结论是:

  • 采用 pgvector;
  • 采用另一个 PostgreSQL 扩展;
  • 使用外部服务;
  • 使用精确检索;
  • 现在不做。

候选没有绑架问题。

决策元数据

最小字段:

id: ADR-023
status: proposed
owners:
  product: ...
  application: ...
  database: ...
  platform: ...
created_at: ...
review_at: ...
decision_scope:
  environment: ...
  postgresql: ...
  pigsty: ...
  os_arch: ...

状态只用明确集合:

proposed -> pilot -> accepted
                    -> rejected
accepted/rejected -> superseded by ADR-N

不要把 pilot 当没有期限的半批准。它必须有 traffic/data/environment 边界、 停止标准和截止复审日。

问题陈述

写:

current behavior
observed evidence
business/technical impact
target SLO/quality
in scope
out of scope
do-nothing consequence

示例:

当前标题检索的零结果率为 X;
经标注样本确认 Y% 来自一个字符拼写误差;
目标只覆盖英文产品标题,返回上限 20,P95 < 50 ms;
中文分词、语义相关性和全站文档不在范围;
不改变时影响为 Z。

每个数字链接到 query snapshot、dashboard 或数据集版本。没有证据的假设 单独列:

assumptions:
  - typo distribution remains stable
  - title updates are below ...
  - one cluster can hold index within ...

后续证据推翻假设时自动触发复审。

候选集合

至少包含:

  1. 不做;
  2. PostgreSQL 原生机制;
  3. 候选扩展;
  4. 外部服务/应用实现(若实际可行)。

对每个候选用同一维度:

维度不做原生扩展 A外部服务
正确性/质量
P95/P99
写入与资源成本
一致性
HA/恢复
升级/供应
权限/安全
退出成本
团队技能/owner

不要把“扩展一行 SQL”与“外部服务完整运维”比较;每格都是完整方案。

成功标准与停止标准成对出现

示例:

success:
  relevance_at_20: ">= 0.82"
  p95_ms: "<= 50"
  p99_ms: "<= 100"
  replica_lag_p95_s: "<= 2"
  clean_restore: pass
  upgrade_rehearsal: pass

stop:
  crash_or_corruption: immediate
  wrong_result: immediate
  p99_ms: "> 200"
  wal_multiplier: "> 3"
  restore_rto: "> agreed budget"
  no_portable_export: reject

“比现在快”不是标准;“无明显问题”不是停止线。

分离硬门槛与权重

某些条件不可用加权分抵消:

hard gates:
  license approved
  target packages available on all nodes
  no correctness regression
  clean restore passes
  exit artifact exists
  security boundary accepted

weighted trade-offs:
  latency
  cost
  operator effort
  feature richness

否则一个非常快但不能恢复的扩展,可能用性能分“赢”过恢复硬门槛。

决策声明

结论写成:

We accept X
for problem Y
in environment/version boundary Z
because evidence A/B/C passed.

We do not approve M/N.
Residual risks are R.
Before production, gates G must pass.
Review is triggered by T.

这比“综合考虑后决定采用”更容易审计。

14.6.2 最小 PoC、风险清单与退出路径

PoC 的最小不是样本最少

最小 PoC 是覆盖决策最关键不确定性的最小实验。它不需要模拟所有生产流量, 但不能只跑 happy path。

扩展通用 PoC:

identity
  server/package/control/library/object versions

install
  intended role success
  unauthorized role failure
  preload/restart if required

behavior
  correctness and representative query
  indexes/plans
  boundary and adverse data

lifecycle
  update path
  update before/after regression
  physical standby/failover
  logical/dump behavior
  clean restore
  major upgrade clone

exit
  portable export
  dependency inventory
  removal without CASCADE

本章本地 PoC 覆盖其中 install、behavior、object update、dump 与文本出口; 没有覆盖 Pigsty L1、备库、clean restore 和 major upgrade,所以 vector 只能是 pilot。

fixture 必须确定性

记录:

  • schema/data version;
  • 生成方式;
  • 随机 seed;
  • 数据规模与分布;
  • query 参数;
  • expected rows/order/error;
  • baseline checksum。

本章不是比较浮点的无限精度,而固定六位小数与 top ID:

trigram scores:
  0.620690,0.305556,0.205128

vector L2:
  0.000000,0.141421,0.282843

对于近似索引,大数据 PoC 应定义 recall tolerance,而不是错误要求每次物理 计划与结果顺序完全相同。

正向、负向、破坏性测试分层

read-only:
  catalog, availability, plan, dependency

reversible DDL in isolated lab:
  CREATE/ALTER/DROP extension

fault injection:
  missing library, wrong preload, failover, crash

destructive lifecycle:
  restore, major upgrade, exit conversion

后两类必须在隔离 clone/L1 进行,有明确 target 与恢复路径。不要为了完成 ADR 在生产主库拔动态库。

本书 lab 的 destructive action 只接管:

pg36_shop/shop_ch14/pg_trgm+vector

并要求 marker、token、target 与无活跃 worker。生产迁移另写,不复用 “删掉重建”脚本。

evidence 不是终端滚屏

每轮输出一个不可变目录:

manifest.txt
package-manifest.txt
available-versions.csv
extension-inventory-before/after.csv
member-catalog-before/after.csv
security-catalog.csv
behavior-before/after.csv
plans
failure stdout/stderr/exit
database-schema.sql
selected-schema.sql
portable-export.csv
verify.txt
review.txt

manifest 包含:

captured_at
target/service
server/tool versions
validation path
source file hashes
proposal checksum

不要写密码、连接 URI secret 或生产个人数据。

风险清单有 owner 与触发器

风险概率/影响缓解观测ownertrigger
package 在新 PG major 缺失提前构建/替代release matrixmajor roadmap
C library crashcanary/rollbackcrash/restarterror budget
ANN recall 漂移golden corpusquality jobmodel/data change
restore 缺旧脚本repo snapshotrestore drillretention review
vendor/license 改变legal/exitperiodic reviewnew terms
node package driftPigsty convergenceparity probefailover/new node

没有 owner 的风险不是被管理,只是被记录。

退出路径从依赖图开始

SELECT
    d.classid::regclass,
    d.objid,
    d.deptype
FROM pg_depend AS d
JOIN pg_extension AS e
  ON e.oid = d.refobjid
WHERE d.refclassid = 'pg_extension'::regclass
  AND e.extname = 'vector';

还要查引用扩展成员的业务对象。退出步骤必须显式:

export/copy
  -> verify
  -> dual representation
  -> switch reads
  -> stop old writes
  -> remove business dependencies
  -> DROP EXTENSION RESTRICT
  -> remove preload/restart
  -> remove packages from nodes/repository only when safe

最后一步不是第一步。包删除前要考虑历史备份与降级节点。

验证退出,而不是只验证导出

退出 PoC 成功条件:

  • 导出行数/主键/checksum 匹配;
  • 目标表示能承载单位、坐标系、模型与精度;
  • 新查询结果和 SLO 在容差内;
  • 旧应用与新 schema 的兼容窗口成立;
  • 无残余 view/function/index/table 依赖;
  • DROP EXTENSION 在不使用 CASCADE 时成功;
  • 包与 preload 清理后实例重启、备库和恢复通过。

14.6.3 结论的版本范围和复审触发器

ADR 是带范围的结论

错误:

pgvector is approved.

可执行:

vector 0.8.4 is approved for a bounded pilot
on upstream PostgreSQL 18.4 / Ubuntu 24.04 amd64 / Pigsty 4.4,
using dimension D and model M,
for corpus C and query shape Q,
under package build B and SLO envelope E.

范围外不是自动拒绝,但必须重新验证。

版本块

scope:
  postgresql:
    implementation: upstream
    versions: ["18.4"]
  pigsty: ["4.4"]
  os_arch: ["ubuntu-24.04-amd64"]
  extension:
    sql_name: vector
    object_version: "0.8.4"
    package_build: "..."
  topology:
    primary: 1
    physical_standby: 2
  workload:
    corpus_version: "..."
    model: "..."
    dimension: 1536
    distance: cosine

“支持 PG14–18”可以是项目宣称;ADR 的验证范围可能只完成 17/18。两者分列。

复审触发器

日历触发:

每 6/12 个月
扩展或 PostgreSQL EOL 前
license/support 合同续签前

变更触发:

  • PostgreSQL major/minor 或内核供应者变化;
  • Pigsty release、OS、CPU architecture 变化;
  • extension project/package/object version 变化;
  • control 的 trusted/preload/requires/relocatable 变化;
  • 数据规模、分布、语言、模型、维度、距离度量变化;
  • 新建/替换 standby、灾备或恢复镜像;
  • SLO、错误预算或容量越界;
  • crash、错误结果、安全通告;
  • 维护者、许可证、供应商或仓库变化;
  • clean restore/upgrade drill 失败;
  • 退出成本估算越过窗口。

不覆盖历史,使用 supersede

决策改变时:

ADR-014 accepted pg_trgm 1.6 in scope X
ADR-028 supersedes ADR-014 for scope Y

保留旧 ADR:

  • 能解释旧备份/旧服务为何依赖它;
  • 能追踪当时证据;
  • 能区分错误决策与条件变化;
  • 能为事故和退出提供历史。

只在原文底部改“现在改用 Z”,会抹掉因果链。

把复审接入变更门禁

自动检查:

inventory package version changed
pg_extension extversion changed
control/library hash changed
server major changed
model/corpus identity changed

若任一发生:

baseline no longer matches
  -> block silent promotion
  -> open review
  -> run scoped test matrix
  -> issue new proposal checksum

不要让监控自动决定架构,但让它阻止“版本已经漂了,ADR 仍显示已批准”。

供第 15–17 章复用

后续三章沿用同一模板,但各自增加领域项:

第 15 章检索

language/tokenizer/dictionary
ranking and relevance corpus
query grammar and denial-of-service boundary
index pending-list/bloat/update cost

第 16 章时空

SRID/coordinate order/unit
geometry validity
spatial selectivity
time zone and temporal range
GIS export format

第 17 章分析与分布式

shard key/co-location
cross-shard transaction
rebalance/failure
columnar/OLAP consistency
capacity crossover point

它们可以增加字段,不能删掉供应、恢复、权限和退出。

ADR 验收问题

评审者逐句问:

  • 问题是否在没有候选扩展名时仍成立?
  • 是否有“不做”和原生替代?
  • 成功/停止标准是否能机器或人工复验?
  • 是否写了 exact server/package/object 版本?
  • 是否测过未授权失败?
  • 是否覆盖备库、clean restore 和 major upgrade?
  • 自定义数据能否导出,退出是否不用 CASCADE
  • 残余风险是否有 owner?
  • 哪个变化会让结论失效?
  • evidence 能否由另一位工程师重跑?

任一回答“以后再补”,ADR 状态最多是 proposed/pilot。

本节结论

好的扩展 ADR 不是“为什么喜欢它”,而是一个可撤销承诺:

under these facts,
for this problem,
this option passes these gates,
with these residual risks,
until one of these triggers changes.

它让采用扩展成为受控工程选择,而不是永久信仰。


上一节:用 Pigsty 管理扩展可用性 · 返回本章目录 · 下一节:实战:评审三个候选扩展 · 查看全书目录 · 查看索引中心

最后更新于