跳至内容
24.1 服务目录与责任模型

24.1 服务目录与责任模型

PostgreSQL 集群是技术对象,服务是责任对象。

technical object
  cluster pg-test
  members pg-test-1/2/3
  ports 5433/5434/5436/5438
  database test

service object
  pg36_shop
  journey place-order / read-order
  owner / dependency / SLO / escalation / evidence

一个集群可以承载多个服务;一个服务也可以依赖多个数据库、队列和外部接口。 若资产目录只记录 IP、实例和版本,事故发生时仍不知道谁能决定:

  • 是否暂停下单;
  • 是否允许读到旧数据;
  • 是否执行 failover;
  • 是否接受恢复到某个时间点;
  • 是否通知受影响用户;
  • 是否冻结发布;
  • 谁能关闭事件。

本节先把这些决定分配给职责,再讨论服务等级、依赖与健康证明。

24.1.1 服务所有者、数据所有者与平台所有者

owner 不是“出问题时帮忙的人”

owner 是对某类决定最终负责的职能。它可以把任务委托给执行者,但不能把 accountability 变成“大家共同负责”。

本章采用四个稳定职能:

职能最终负责什么不应独自决定什么
service owner用户旅程、SLO、发布优先级、业务降级数据含义、底层恢复细节
data owner数据语义、质量、保留目的、隐私分类集群拓扑与数据库执行步骤
platform ownerPostgreSQL/Pigsty、容量、备份恢复、平台执行用户可接受的损失与业务优先级
security/privacy访问政策、安全例外、证据披露、隐私升级正常业务功能取舍

这四者不是四个超级管理员。理想状态恰恰相反:

service owner          does not need database superuser
data owner             does not need shell access
platform owner         does not invent data meaning
security/privacy       does not run every routine migration

权限和责任要能分开。第 23 章已经把 login、runtime、owner 与 break-glass 角色拆开;本章把组织责任也做同样的拆分。

service owner

service owner 负责从用户视角定义合同:

journey:
  place-order

eligible:
  authorized, valid request admitted by the application

good:
  success returned and idempotency token reconciles to one committed order

degradation:
  stop new writes, preserve read-only status lookup

它不能只写“数据库可用”。若应用在 PostgreSQL 正常时返回 500,用户仍然 没有获得服务。

service owner 还要在错误预算耗尽时决定:

  • 暂停哪些功能发布;
  • 哪些可靠性工作优先;
  • 是否启用产品降级;
  • 哪些业务风险值得例外。

这些决定必须与 platform owner 共同评审技术可行性,但不能完全下放给 DBA。

data owner

data owner 负责说明“一行数据代表什么”和“错误意味着什么”:

order_id          是否全局唯一
tenant_id         谁能看见
amount            使用什么货币和舍入规则
status            允许哪些状态迁移
committed order   用户是否已经获得不可撤销承诺

恢复时,platform owner 可以证明 PostgreSQL 启动、system identifier 正确、 恢复目标已经到达;data owner 仍要判断:

  • 目标时间是否符合业务容损;
  • keep 应当存在、discard 应当不存在是否足够;
  • 订单、库存和支付是否需要跨系统核对;
  • 哪些差异要停止业务而不是继续恢复。

因此“数据库恢复成功”与“业务恢复可接受”是两个验收签名。

platform owner

platform owner 维护的是可交付数据库服务:

  • Pigsty inventory 和渲染产物;
  • PostgreSQL 初始化与运行参数;
  • Patroni/etcd 角色与控制面;
  • HAProxy/PgBouncer 入口;
  • pgBackRest/WAL 恢复路径;
  • 容量、升级、安全基线;
  • 指标、日志、告警与值班执行。

它必须能把平台事实翻译成服务后果。例如:

pg-test-2 replay lag rises
  -> affected path: replica reads
  -> user consequence depends on read routing and freshness contract
  -> primary writes may still be healthy
  -> do not page the service owner merely because one cause metric is high

平台 owner 也不能用“基础设施都绿”关闭事故。关闭条件应来自用户 SLI、 数据核对与恢复验证。

security/privacy owner

数据库治理产生敏感证据:

  • 谁请求、批准和执行;
  • 哪个身份获得了什么权限;
  • 哪条查询失败;
  • 哪个租户或事件受影响;
  • 备份和日志保留多久;
  • incident evidence 向谁披露。

security/privacy owner 决定访问、例外和披露边界。它不意味着把所有日志永久 保存。收集过多原始 SQL、bind value 或客户行,会让“审计系统”变成新的数据 泄露面。

incident commander 不是第五个永久 owner

incident commander 是事件期间的协调角色:

declares severity
maintains decision log
assigns technical lead
coordinates communication
checks stop conditions
decides next checkpoint
closes or hands off incident

它可以由 service owner 职能担任,也可以按事件规模另行指定。技术 lead 负责执行和验证,不应同时独占业务影响判断、通信和所有批准。

使用职能身份,不把人名写死在合同里

服务卡中的:

{
  "function": "platform",
  "role_id": "database-platform-owner",
  "on_call_route": "route://db-platform-oncall"
}

描述稳定接口。真实系统再把 role_id 映射到:

  • 身份目录 group;
  • 当前 primary/secondary on-call;
  • 可达的通知渠道;
  • 时区与交接;
  • 替补和 manager escalation。

只写“找小王”有三个问题:

  1. 人员变化会让文档瞬间过期;
  2. 不知道非工作时间找谁;
  3. 个人名字不能证明权限和当班状态。

反过来,只写一个永远没人测试的 db-oncall@example 也不算 owner。路由必须 通过 notification canary 定期证明可达。

不要把 RACI 做成责任迷宫

RACI 可以帮助列出 Responsible、Accountable、Consulted、Informed,但最常见 的失败是每个格子都填满:

five accountable owners
ten consulted teams
no person authorized to stop

对一个决定,应当尽量有一个最终 accountable function:

决定ARC
修改用户 SLOservicereliability analystplatform/data
执行 planned switchoverplatformqualified operatorservice
接受恢复点dataplatform recovery leadservice/security
暂停下单serviceapplication operatordata/platform
批准高权访问security/privacyidentity adminplatform/data

“A” 不是可以跳过技术门禁的权力。service owner 可以要求恢复服务,但不能 要求 platform operator 在 fencing 未知时强制 promote。

所有权的验收问题

每个 owner 都应回答三类问题:

decision
  我能批准或拒绝什么?

evidence
  我需要看见哪些事实?

absence
  我不在时由哪条已测试路径接替?

若答案只有“出了事群里讨论”,责任模型尚未建立。

24.1.2 等级、规格、依赖、值班与升级路径

服务等级是一组义务

goldsilverbronze 如果没有义务,只是颜色:

Gold PostgreSQL
  ? on-call coverage
  ? SLO
  ? restore frequency
  ? RTO/RPO
  ? upgrade deadline
  ? security review
  ? capacity headroom
  ? evidence retention

可执行的 tier 应当打包:

维度需要固定的内容
availability用户 SLI、目标、窗口、预算政策
recovery恢复类型、证据新鲜度、演练频率
support值班时段、确认目标、升级链
change风险级别、批准、窗口、冻结规则
capacityheadroom、预测周期、扩容 lead time
security认证、加密、轮换、审计与例外
lifecyclePostgreSQL/Pigsty 版本和升级时限
evidence保留期、访问、完整性与删除

本章的 sandbox-reference 明确写:

production tier        false
on-call                illustrative route only
capacity               no laptop sizing inference
restore                one retained sandbox run
change                 L2/L3 independent authority
security               mechanism evidence, production gaps retained

这比给沙箱贴上“Silver”诚实得多。

规格不是只有 CPU 和内存

数据库 service specification 至少有四组:

用户规格

  • 关键旅程;
  • 可用性、延迟、正确性、新鲜度;
  • 写后读、一致性和降级行为;
  • 支持时段和沟通。

数据规格

  • 数据分类;
  • 主权和保留;
  • 容许丢失和恢复粒度;
  • tenant/authorization 边界;
  • 核对不变量。

技术规格

  • PostgreSQL major 与扩展;
  • 拓扑、同步策略、入口;
  • pool mode 与连接预算;
  • 备份、WAL 和恢复设施;
  • 监控、日志和依赖。

运营规格

  • owner/on-call;
  • SOP 和演练;
  • 变更冻结;
  • 证据与审计;
  • 已接受例外和到期日。

只记录 4C16G500G,不能回答任何恢复、安全和服务问题。

依赖必须写 failure semantics

依赖表不能止于“uses PostgreSQL”:

依赖关系失败语义
application runtime发出用户事件、提交事务PG 健康时应用仍可拒绝或错误提交
HAProxy/PgBouncer承担入口与池化直连主库成功不代表应用入口成功
PostgreSQL事务与持久状态连接成功不代表业务事务正确
Patroni/etcd角色和切换控制控制面受损可先阻止安全切换
pgBackRest/WAL恢复路径backup exists 不代表可恢复
Victoria stack观察和告警telemetry missing 会把状态变成 unknown

failure semantics 回答:

dependency fails
  -> which journey is affected?
  -> fail closed, fail open, degrade, or become unknown?
  -> who owns first diagnosis?
  -> what is the first safe action?

例如 etcd 暂时不可用时,现任 primary 可能继续服务;真正受损的是安全 role change 能力。若把“etcd member down”直接等同于用户 outage,会制造误报; 若完全忽略,又会在需要 failover 时才发现控制面失效。

把共享故障域写进依赖

第 19 章的四台 VM 看起来有四个地址,但共享:

  • 一台 laptop;
  • 一个 hypervisor;
  • 一套供电和网络;
  • 同一底层存储;
  • 单节点 etcd;
  • 单一 MinIO/control host。

因此拓扑图中的三节点不能推出三个独立 failure domain。依赖模型应同时表达:

logical redundancy = 3 PostgreSQL members
physical independence = not established

这也是为什么服务卡保留 known production gaps,而不是把它们埋在实验日志里。

值班路径需要输入与输出合同

一条值班 route 至少固定:

input
  severity
  service id
  user impact
  start time
  alert id
  dashboard
  runbook

output
  acknowledged by whom
  incident id
  technical lead
  next update time
  decision log

确认时限不是修复时限:

acknowledge 5 minutes
  != resolve 5 minutes
  != RTO 5 minutes

ack 只证明有人接管。恢复目标必须按故障类别、数据边界和服务合同另行定义。

escalation 不是把同一消息抄送更多人

有效升级改变权力、资源或沟通:

SEV-2
  service on-call + platform on-call
  bounded user degradation

SEV-1
  incident commander
  data owner for correctness/recovery decision
  security/privacy for breach or evidence handling
  executive/customer communication when required

升级触发可以来自:

  • 影响范围扩大;
  • 数据正确性或保密性受威胁;
  • 错误预算快速燃烧;
  • 操作超过停止线;
  • recovery path 不确定;
  • 事件超过时间阈值;
  • 现有 authority 不足。

不要只按“CPU 超过 90%”升级。CPU 是原因候选,不是业务严重度。

依赖与升级的服务卡片段

本章完整文件见 service-card.json。其中一项依赖:

{
  "id": "pgbackrest-repository",
  "kind": "recovery-system",
  "relationship": "stores base backup and WAL needed for recovery",
  "failure_semantics": "a recent backup job does not prove the selected recovery point is usable",
  "owner_function": "platform"
}

owner_function 负责第一技术响应;最终恢复点是否可接受仍需要 data/service owner。

服务目录的最小字段

identity
  service_id / display_name / environment / catalog_status

purpose
  business capability / customer journeys / critical operations

scope
  data class / production boundary / database / cluster / entrypoints

ownership
  service / data / platform / security

tier
  explicit obligations

dependency
  relation / failure semantics / owner

health
  user contract and component layers

escalation
  severity / trigger / role / acknowledgement

governance
  SLO policy / SOP catalog / evidence policy / known gaps

每次更改服务卡,应检查对应的 SLO、告警 route、SOP 与权限是否一起更新。

24.1.3 实例健康不等于业务服务健康

六层证明

本章使用六层健康链:

1 process
  expected daemon exists

2 endpoint
  declared client path is reachable and routes correctly

3 authentication
  intended identity over intended transport can authenticate

4 transaction
  intended operation can commit and its outcome can be reconciled

5 correctness
  domain, tenant and authorization invariants hold

6 durability/recovery
  acknowledged state survives declared failures and can be restored

没有任何一层单独足够。服务健康还必须满足用户合同。

process alive 只证明进程事实

systemctl is-active postgresql 或 exporter 的 up 指标能证明采集时进程存在。 它不能证明:

  • postmaster 接受连接;
  • 监听的是正确地址;
  • HBA 允许目标身份;
  • server 是正确集群;
  • 当前节点可写;
  • 磁盘还有空间;
  • transaction 能提交;
  • 应用 SQL 正确。

进程指标适合组件诊断和自动重启,不应直接成为业务 availability 分子。

pg_isready 也有边界

pg_isready 检查 PostgreSQL server 的连接状态,返回 accepting、rejecting 或 no response。它不需要提供正确用户名、密码或数据库才能获得 server status;错误参数还可能在服务器日志留下失败连接。官方边界见 pg_isready

因此:

pg_isready success
  -> a PostgreSQL server at this endpoint is accepting connection attempts

not proven
  -> intended application can authenticate
  -> intended database and role are correct
  -> intended transaction succeeds

SELECT 1 证明得更多,但仍不够

使用真实入口、真实 TLS 约束、合成身份执行:

SELECT
  current_database(),
  session_user,
  current_user,
  pg_is_in_recovery(),
  current_setting('server_version');

能证明:

  • 网络和 PostgreSQL 协议;
  • 认证;
  • database/role 身份;
  • 当前节点 recovery 状态;
  • 简单 query path。

它仍然绕过:

  • 业务表;
  • lock/constraint/RLS;
  • write permission;
  • commit;
  • connection pool session semantics;
  • 应用序列化和错误映射。

transaction probe 必须处理未知结果

更接近用户的 probe:

generate unique synthetic token
  -> call declared application or database write path
      -> commit
          -> query token through declared result path
              -> classify exactly one of:
                   committed once
                   absent
                   duplicate
                   unknown

连接在 COMMIT 附近断开时,客户端可能不知道事务是否已经提交。直接重试会 造成重复。probe 和 Runbook 都必须使用幂等 token 核对结果。

第 20、22 章的切换演练正是按:

acknowledged
unknown committed
unknown absent
duplicate
unreconciled

分类,而不是把所有连接错误都计为“数据库没写入”。

correctness 不能由事务成功代替

下面都可能 commit 成功:

  • 订单写到了错误 tenant;
  • 金额舍入错;
  • 同一个 idempotency token 生成两张订单;
  • RLS context 泄漏;
  • 状态从 cancelled 跳回 paid
  • 应用返回失败但后台已提交。

所以 good availability event 必须包含结果核对,correctness control 还要独立 运行领域 reconciliation。

PostgreSQL constraint、unique index、foreign key、RLS 与 transaction isolation 是防线,不是所有业务正确性的完整证明。

replica “时间延迟”会在空闲时误导

常见查询:

SELECT now() - pg_last_xact_replay_timestamp();

在没有新 WAL 的空闲系统中,这个差值会持续增大,即使 replica 已完全追平。 它回答“最后一个已 replay transaction 的时间距现在多久”,不自动等于当前 replication lag。

对写后读新鲜度,应使用:

commit-correlated token
  write through declared write path
  record commit outcome
  poll declared read path
  measure visibility bound

诊断时再结合:

  • primary 与 replica WAL LSN distance;
  • pg_stat_replication
  • pg_stat_wal_receiver
  • replay pause/conflict;
  • route 选择;
  • 客户端时钟。

PostgreSQL 18 的统计视图目录见 Monitoring Database Activity

cluster healthy 也不等于 entrypoint healthy

可能出现:

Patroni:
  one leader + two streaming replicas

but:
  HAProxy still routes old leader
  PgBouncer holds stale server connections
  DNS/VIP is unreachable from application network
  client certificate name mismatches
  pool user is absent

因此健康检查要从用户网络和声明入口执行。直接 SSH 到 primary 后 psql 成功 只能作为绕过入口的诊断事实。

Pigsty 提供组件视角,不替应用发明 good event

Pigsty 能关联:

典型事实
hostCPU、memory、disk、network、kernel
PostgreSQLactivity、transactions、locks、WAL、I/O
PgBouncerclients、servers、wait、pool
HAProxyfrontend/backend/session/health
Patroni/etcdrole、timeline、control state
pgBackRestbackup/check/log
observabilityscrape、rule evaluation、notification

clsinsip 让这些事实能关联到同一个 Pigsty 对象。应用仍需要提供:

  • operation class;
  • eligible/good outcome;
  • user latency;
  • commit token;
  • domain reconciliation;
  • service/environment。

不要在时序标签里放 order_idtenant_id、完整 SQL 或 error message。它们会 造成无界 cardinality,也可能泄露数据。

三个判断练习

情形 A:一台 replica down,用户指标正常

user availability       healthy
freshness               healthy
remaining redundancy    degraded

处理:

  • 不必重复 page 所有业务 owner;
  • platform ticket 或受控事件;
  • 检查另一 replica、WAL 保留与恢复能力;
  • 若 redundancy policy 已触及耐久性停止线,可升级。

情形 B:三台 PostgreSQL 都绿,下单 100% 失败

database component      healthy
service availability    failing

处理:

  • page service symptom;
  • 检查应用 release、identity、pool entry、schema compatibility;
  • 不要因为 PG dashboard 绿色而关闭;
  • platform 指标用于定位原因。

情形 C:请求 99.999% 成功,但出现一条跨租户数据

ratio availability      excellent
correctness control     failed
severity                potentially SEV-1

处理:

  • 冻结相关写入;
  • 保留 reconciliation boundary;
  • security/privacy 与 data owner 加入;
  • 不能用充足错误预算继续发布。

健康矩阵

观测可以证明不能证明
process activedaemon 存在endpoint/auth/transaction
pg_isreadyserver 接受连接尝试身份、业务 SQL
authenticated SELECT 1入口、认证、querywrite/commit/correctness
write token visible某次事务与可见性全量业务正确
reconciliation zero已覆盖不变量未见差异未覆盖规则、未来恢复
restore drill某份证据下可恢复所有故障、生产 RTO
user-event SLI窗口内用户结果根因

这张表说明为什么需要两套视角:

SLI tells whether users are hurt
component telemetry tells why and what to do

服务卡审查清单

  • service_id 是否稳定且不等于某台机器?
  • 是否列出关键 user journey 与 operation class?
  • service/data/platform/security 是否各有明确 accountability?
  • owner 是否映射到可测试 route,而不是个人名字?
  • tier 是否列义务,而不是颜色?
  • 每个依赖是否写 failure semantics 和 owner?
  • logical redundancy 与 physical failure domain 是否分开?
  • severity 是否来自用户、数据和恢复后果?
  • instance、cluster、endpoint 和 service health 是否分开?
  • synthetic probe 是否使用真实入口、身份和业务路径?
  • commit 附近的 unknown outcome 是否可核对?
  • correctness 和 durability 是否有独立 control?
  • known production gaps 是否在服务卡而非某个聊天记录里?

完成这张服务卡后,下一节才能计算 SLO。否则百分比没有分子、分母、责任人或 决策后果。


返回本章目录 · 下一节:SLI、SLO 与错误预算 · 查看全书目录 · 查看索引中心

最后更新于