跳至内容
18.1 从数据库产品到能力组合

18.1 从数据库产品到能力组合

当团队说“我们用 PostgreSQL”时,这句话通常混合了三种不同事实:

product
  一个特定版本的 PostgreSQL server

capabilities
  事务、约束、检索、时空、分析、复制、恢复……

service
  带身份、入口、目标、配额、支持和生命周期的对外交付

产品可以启动,不代表所有能力可用;能力可以运行,不代表服务可承诺。平台 设计的第一步,是把这三层重新拆开。

18.1.1 事务、检索、时空、分析与任务能力

从业务问题开始,而不是从组件清单开始

pg36_shop 至少需要处理以下业务问题:

业务问题需要的能力首选正确性边界
订单与库存能否保持不变量关系约束、事务、并发控制PostgreSQL commit
应用如何安全调用数据能力角色、schema、prepared SQL、API 合同DB + 应用
商品如何被关键词找到全文/模糊检索、排序、质量 goldenPostgreSQL 起步
商品如何按语义相似找到embedding、向量距离、ANN 质量试点
配送事件在哪里、何时有效空间、时间、边界和参考系PostgreSQL 起步
月报如何快速且不过度影响交易并行、索引、汇总、离线读PostgreSQL + 隔离
订单事件如何送到其他服务outbox、relay、消息投递跨系统合同
图片字节放在哪里对象存储与元数据协调按数据域拆分

先写能力,能避免两种常见偷换:

“PostgreSQL 支持” -> “我们的服务已经支持”
“引入了某产品”   -> “业务问题已经解决”

例如,vector 扩展已经在第 14 章的开发 fixture 中安装,<=> 距离查询也在 第 15 章得到正确结果。这证明“语义检索试验可运行”,没有证明:

  • embedding 模型会被稳定版本化;
  • ANN 在生产规模下满足质量与延迟;
  • 索引重建落在维护窗口;
  • 副本、备份、恢复和升级路径全部可用;
  • 团队可以在模型漂移时诊断结果变化。

所以它的生命周期是 pilot,不是 accepted

事务能力是权威状态的锚

对订单、库存和支付,最重要的不是“能存 JSON”或“QPS 很高”,而是所有 写入者看到同一套不可违反的事实:

order total = sum(order item totals)
payment currency = order currency
inventory cannot be consumed below the approved boundary
status transition belongs to a finite allowed graph
duplicate request does not create a second business effect

第 4、10、13 章分别从约束、并发与数据库逻辑证明了这些能力。只要这类状态 仍由 PostgreSQL 定夺,缓存、搜索索引、事件流和湖仓都只能是派生物。

“source of truth” 容易变成口号,更精确的写法是按数据域声明 authority:

product business state          -> PostgreSQL
cache entry bytes               -> cache
order publication intent        -> PostgreSQL outbox
message delivery/replay log     -> event bus
media object bytes              -> object storage
media identity/state/checksum   -> PostgreSQL
analytical projection           -> lakehouse
operational business state      -> PostgreSQL

冲突时相信谁,必须在发生冲突前写清楚。

检索是一组能力,不是一条 LIKE

商品检索至少可以分成:

exact identity lookup
prefix / substring
typo-tolerant fuzzy match
lexical relevance
phrase / field weighting
semantic similarity
filter + rank
faceting / aggregation
highlighting
freshness and deletion

第 15 章的质量 golden 证明 pg_trgm 适合当前模糊检索基线,vector 适合 受控 pilot。它没有把“搜索”宣布为永久留在 PostgreSQL。蓝图保存一个明确 触发器:

当质量、规模、语言能力或独立可用性目标击败 PostgreSQL 基线时,才启用 external-search-projection-v1

这样,外部检索是一个由证据触发、可重建、可退出的投影,而不是架构图里一 开始就存在的时髦方框。

时空能力先统一语义,再比较引擎

空间系统最危险的错误往往不是查询慢,而是答案看起来合理:

SRID 混用
经纬度顺序颠倒
边界包含规则不一致
event time 与 ingest time 混淆
本地时区被当 UTC
有效时间区间重叠
迟到事件被静默丢弃

第 16 章把 EPSG:4326、UTC、区间与边界规则固化为 fixture。PostGIS 让空间 类型、操作符与索引进入 SQL,但业务合同仍然高于扩展:迁移到其他引擎时, 这些语义必须不变。

因此 capability 的结构至少要包含:

{
  "placement": "postgresql",
  "system_of_record": "postgresql",
  "state": "conditional",
  "consistency": "UTC + versioned validity + EPSG:4326",
  "freshness": "event ingest plus measured lateness",
  "externalization_trigger": "retention or throughput misses objective"
}

分析能力先减少工作,再横向扩展

第 17 章已经建立顺序:

正确性 golden
  -> 计划与统计
  -> 索引 / BRIN
  -> 并行
  -> spill 证据
  -> 汇总
  -> OLTP/OLAP 隔离
  -> 分布式门槛

当前蓝图选择“本地汇总 + offline replica”作为第一步,而不是选择 Citus。 这不是永久拒绝分布式;第 26 章的容量证据可以触发新 ADR。

同理,postgres_fdw 的 loopback fixture 只证明过滤、聚合和部分失败的 查询形状。PostgreSQL 官方 Foreign Data 说明外表通过 wrapper 访问外部数据,并通过 user mapping 提供认证信息。 本书实验使用的 password_required=false 没有生产身份、网络与故障域, 所以严格标为 lab-only

任务能力要分事务内与事务外

“数据库里能执行函数”不等于“任何业务任务都应放进事务”。一个实用边界:

留在事务内:

约束检查
小而有界的派生值
幂等状态转换
短路径的 outbox 写入
与当前事务必须原子完成的审计事实

移到事务外:

HTTP / RPC
发送邮件或短信
大批量重算
不确定时长的模型推理
跨系统补偿流程
无限或长期重试

事务内代码失败可以回滚;远端世界通常不能跟着 PostgreSQL 回滚。把两者硬塞 在一起,会产生持锁时间、连接占用、重试重复和不可控级联。

能力清单必须有状态

本章采用以下生命周期词汇:

状态含义
accepted已有当前范围证据,仍受版本与服务门约束
accepted-with-scope只在明确狭窄边界内接受
accepted-first-step当前首选,但容量触发器仍待观察
conditional前置门尚未全部通过
pilot只允许受控试验,不进入默认生产服务
lab-only教学机制证据,禁止生产准入
deferred触发条件未出现,不增加系统

没有状态的能力清单会把“听说过”“装得上”“试过一次”和“可值班”放在同一 列,最终无法治理。

18.1.2 计算、存储、接入、控制与观察平面

能力回答“要做什么”,平面回答“由哪类机制完成”。

数据与计算平面

数据/计算平面直接处理请求与业务状态:

PostgreSQL backend
tables / indexes / WAL-visible changes
SQL planner and executor
constraints / functions / triggers
extension types and operators
replica read execution
external projection workers

它的典型证据是:

  • SQL 结果和业务校验和;
  • 执行计划与实际行数;
  • 事务、锁与 SQLSTATE;
  • replica replay 位置;
  • 投影 watermark。

在这个平面上,“成功”意味着某次业务操作按合同完成,不代表平台整体健康。

存储平面

存储平面不仅是 PGDATA

存储保存什么关键风险
PostgreSQL data filesheap、index、catalog损坏、容量、延迟
WAL恢复与复制所需变化归档缺口、保留爆炸
backup repositorybase/diff/incr 与 WAL不可恢复、凭据、同域失效
tempsort/hash 等中间结果磁盘耗尽、I/O 争用
object storage媒体或备份对象清单、版本、删除
cache可丢弃派生数据陈旧、穿透、错误权威
analytical/search index可重建投影lag、语义漂移、删除遗漏

“数据有三份”不是恢复策略。三份流复制副本会复制同一条误删;三个位于同一 存储故障域的节点也不是三个独立副本。第 21、32、35 章会分别验证备份恢复、 PITR 与损坏取证。

接入平面

接入平面把服务语义变成客户端可连接的端点:

name / VIP / address
port
TLS and authentication
pooling mode
target selector
health check
failover routing
connection and queue budget
session-state contract

一个主库 IP 只是位置,不是服务。客户端需要知道:

这个入口是否可写
是否允许陈旧读
是否 read-your-writes
发生切换时连接怎样断开
事务池能否使用 session feature
取消与超时如何传播

Pigsty 的 Service Access 用端口和 selector 表达 primaryreplicadefaultoffline 等服务。 第 22 章会把这些入口与 PgBouncer 语义、连接预算一起验收。

控制平面

控制平面改变系统的期望状态:

inventory and configuration
package and extension versions
cluster membership
leader election
switchover/failover decision
backup schedule and retention
role / database provisioning
change rollout and rollback

控制平面故障与数据平面故障不同。数据库可以继续处理流量,而 inventory 已经 漂移;也可能数据库本身健康,但错误的健康检查把流量切走。

控制平面必须回答:

  • 谁能改;
  • 改什么对象;
  • 如何审阅;
  • 是否幂等;
  • 如何观察收敛;
  • 哪一步是最后可逆点;
  • 失败时由谁接管。

Ansible 成功退出只说明某次自动化执行没有报告失败;它不是业务 SLO 证据。

观察平面

观察平面收集并解释:

metrics
logs
traces
catalog snapshots
query fingerprints and plans
backup manifests
configuration drift
synthetic probes
business invariants

观察平面不应只回答“图绿不绿”,还要让值班者完成因果链:

用户症状
  -> 受影响的服务入口
  -> 当前拓扑与流量目标
  -> 数据库等待/资源/复制/恢复状态
  -> 最近变更
  -> 可逆且风险最小的动作

第 25 章会验证信号到 runbook 的连接。本章只列出必须覆盖的八类信号,不声称 告警已经有效。

管理平面与业务平面不要共用身份

一个常见反模式:

application connection
  = object owner
  = extension installer
  = backup operator
  = cluster administrator

本书 fixture 已把角色分开:

身份当前边界
pg36_appLOGIN、非 superuser、运行时
pg36_ownerNOLOGIN、对象所有者
postgres本地正式实验管理员

这还不是完整生产角色模型。第 23 章要继续拆出迁移、监控、备份、复制、审计 与应急身份。

一项能力会穿过多个平面

以“商品模糊搜索”为例:

data/compute  pg_trgm operator + GIN/GiST plan
storage       product table, index, WAL, backup
access        read endpoint, role, timeout
control       extension package/version, CREATE EXTENSION, schema
observe       latency, quality golden, index build, bloat, errors
governance    owner, lifecycle, upgrade and exit

只验证 SQL 正确,会漏掉四个平面;只部署组件,则连第一项也未必正确。

18.1.3 组件组合必须有统一服务目标

局部健康不推出整体健康

假设请求路径是:

client
  -> DNS/VIP
  -> HAProxy
  -> PgBouncer
  -> PostgreSQL primary
  -> transaction
  -> outbox
  -> relay
  -> event bus
  -> consumer

每个组件都有自己的“up”,但业务关心的是:

订单是否只创建一次
提交后多久可查询
事件多久送达
失败后是否可安全重试
是否会丢、重、乱序
能否在目标时间内恢复

如果数据库 20ms 提交、relay 卡 40 分钟,订单 API 的数据库延迟指标仍然很 漂亮,业务事件服务却已经违约。

先定义服务,再分配组件目标

一个服务目标模板:

维度示例
用户动作创建订单
成功定义返回稳定 order_id,状态可读,重复请求无第二次效果
延迟API P95/P99
正确性约束、金额、状态、幂等全部成立
可用性测量窗口、排除项、错误预算
新鲜度提交后 read-your-writes;事件 publish lag
持久性故障模型内的 RPO
恢复场景化 RTO,不只“启动成功”
容量峰值并发、增长与余量
安全身份、租户、数据分类
成本服务单位成本与预算

组件指标从这个目标推导。不要反过来因为某仪表盘有一个指标,就把它升格为 服务 SLI。

可用性相乘只是一种初步直觉

若一条同步路径必须经过多个独立组件,在非常简化的独立假设下:

[ A_{path} = \prod_{i=1}^{n} A_i ]

三个各 99.9% 的串行依赖约为:

[ 0.999^3 \approx 99.7003% ]

这提醒我们“组件都三个九”并不保证路径三个九。但不能把这个公式当精确生产 模型,因为:

  • 故障往往相关,共享网络/电源/配置/身份;
  • 重试、缓存和降级会改变路径;
  • 读写操作依赖不同;
  • 维护与区域故障不是独立伯努利事件;
  • 业务正确性失败可能不表现为组件 down。

真正的目标要通过故障模型、演练和真实 SLI 验证。

新鲜度预算也会叠加

派生投影可能经历:

transaction commit
  -> outbox polling
  -> broker publish
  -> consumer queue
  -> indexing
  -> alias visibility

总 lag 不是只看 broker lag。每一段要有时间戳或位置:

阶段证据
source commitcommit LSN / business version
publication intentoutbox timestamp
brokerpartition/offset
consumeracknowledged source identity
projectionapplied version / watermark
queryserved generation

没有共同 identity,端到端新鲜度无法对账。

正确性优先于可用性包装

“失败时返回旧缓存”可能提高响应可用性,也可能把已取消订单重新显示为有效。 降级必须按数据和操作分类:

public product description
  可允许有标签的短时陈旧

inventory availability
  陈旧读可能导致超卖,不能默认降级

payment state
  不能用缓存猜测

analytics dashboard
  可显示 last complete watermark

同一个缓存组件不能用一个统一 fallback 策略覆盖所有字段。

SLO 目标必须与证据状态绑定

本章目录中的:

"availability_target": "99.9%-proposal"

故意带有 -proposal。要去掉它,至少要经过:

ch19 environment baseline
ch20 HA failure model and drills
ch21 restore evidence
ch22 endpoint and connection behavior
ch23 security controls
ch24 approved SLI/SLO and ownership
ch25 signal and alert exercise
ch26 representative capacity

一项数字若没有:

measurement
window
population
exclusions
owner
alert
runbook
evidence retention

它只是愿望。

统一目标不等于统一部署

服务目标统一,是为了让组件协作;并不要求把组件放在同一主机、同一进程或 同一团队。

反过来,部署在同一 PostgreSQL cluster 也不自动意味着目标相同:

  • 交易写入需要 read-your-writes;
  • 离线分析允许 60 秒 lag;
  • 备份任务关注可恢复性;
  • 搜索 pilot 关注质量与构建时间。

平台要把这些 workload class 显式分开,并为冲突设优先级。

用一个“合同—证据—动作”闭环

每项服务能力最终应形成:

contract
  owner + semantics + objectives + limits

evidence
  SQL/catalog/metric/log/drill/manifest

decision
  accepted / conditional / pilot / rejected

action
  deploy / isolate / tune / externalize / rollback

review trigger
  version / scale / incident / objective / ownership change

本章的四份 JSON 和一个 ADR 正是在演示这个闭环。它们的价值不在文件格式, 而在于架构结论可以被程序拒绝、被证据更新,也可以在条件变化时退出。


返回本章目录 · 下一节:PostgreSQL 的强项与代价 · 查看全书目录 · 查看索引中心

最后更新于