跳至内容

19.1 先写服务需求

部署的第一行不应是:

pg_version: 18

而应是:

这个服务为何存在?
什么数据不能丢?
什么操作不能错?
谁承担结果?
失败多久开始造成不可接受损失?

如果这些问题没有答案,CPU、节点数、同步复制和备份频率都只能靠猜。

19.1.1 业务重要性、数据分类与所有者

先定义业务能力

pg36_shop 提供的不是“一个 database”,而是:

商品浏览与检索
客户身份与地址
订单创建和状态转换
库存与支付事实
配送时空事件
分析与外部投影源

不同能力的故障损失不同:

能力失败影响可接受降级
创建订单直接收入/履约风险拒绝比重复创建安全
查询支付状态财务与客服风险不可用旧缓存猜测
商品描述转化下降可短时有标签陈旧
搜索排序发现能力下降可回退简单检索
分析报表决策延迟可显示 last watermark
图片读取体验下降placeholder/重试

一个统一 database 可以承载它们,但 service objective 不能只写一个“重要”。

业务重要性需要损失模型

常用分级:

tier 0 / critical
  停止即产生重大安全、财务或合规损失

tier 1 / important
  核心业务中断,短时可人工/降级

tier 2 / standard
  影响明显,但可在较长窗口恢复

tier 3 / development
  无生产承诺,可重建

分级必须连接动作:

criticalstandarddevelopment
owner/on-call24×7 明确支持窗口明确工作时间
HA多故障域并演练按目标设计可无
backup跨域、频繁演练标准恢复可选且声明
change强审批/回退标准流程自助边界
capacity高 headroom正常 headroombest effort
incident快速升级标准升级issue

若分级只改变标签颜色,就没有价值。

数据分类决定安全与恢复边界

分类至少包含:

public
internal
confidential
restricted / regulated
credentials and cryptographic material

对每类记录:

  • 数据 owner;
  • 合法用途;
  • 可访问角色;
  • 是否可复制到 dev/test;
  • 加密与审计要求;
  • 地域限制;
  • retention;
  • 删除时限;
  • backup 中如何处理;
  • incident 通知义务。

本章正式 sandbox 只允许:

synthetic teaching data
production_data_permitted=false
production_traffic_permitted=false

这是硬边界。VM 看起来像生产拓扑,也不能把生产数据“临时导入测试”。

数据 owner 与平台 owner 不同

建议至少区分:

角色责任
business/data owner数据用途、正确性、分类、保留、损失
service ownerSLO、错误预算、依赖、发布、事件
database platformPostgreSQL/Pigsty、HA、备份、接入、容量
security/privacy威胁、控制、审计、合规
application teamschema/SQL、连接、重试、兼容、流量
incident commander事件期协调和决策

一个人可以兼任,责任不能消失。

owner 要能作决定

在事故中,DBA 可以说:

“当前恢复到 10:31 会丢 47 秒提交,
 恢复到最新可能保留错误写入。”

但通常不能独自决定哪种业务损失更小。需要提前指定有权选择:

availability versus consistency
restore point
degraded operation
data deletion
customer communication
error-budget spend

“负责人:数据库团队”太宽泛。最终要映射到值班角色、升级路径和替代人。

数据清单要包含派生副本

第 18 章已经定义:

PostgreSQL authoritative business state
cache projection
event delivery/replay log
object bytes
search projection
analytical projection
backup/WAL copies

部署规划不能只列 primary 数据目录。数据流 inventory 应记录:

副本authorityfreshnessretentiondeletionrebuild
replicaPostgreSQLreplay lagcurrentfollows WALbase backup
backuphistorical recoverybackup/WALpolicyretention expiryrestore
cachederivedTTL/versionevictiontombstone/TTLsource refill
event busdelivery logpublish lagbroker policyworkflowreplay/snapshot
lake/searchprojectionwatermarkgenerationtombstonerebuild

这些副本会影响存储、网络、密钥和故障域规划。

分类要进入 inventory 与 evidence,但不要泄密

配置可保存:

service_class: pg-ha-standard
data_class: confidential
owner: shop-order-team

不应把:

customer data samples
passwords
private keys
recovery secrets
token values

写入基线报告。

本章的 inventory projection 只输出安全 allowlist,记录:

source mode
secret-bearing source fingerprint withheld
safe projection sha256
secret fields redacted count
secret values exported = 0

它证明审计过程知道 secret 存在,同时不把值复制到 evidence。

未知 owner 是阻断项

没有 owner 的 service 不应进入生产。原因很现实:

  • 谁批准 maintenance?
  • 谁判断数据正确?
  • 谁接 incident 电话?
  • 谁接受 RPO?
  • 谁决定退役?
  • 谁支付容量?

可以在 sandbox 用 placeholder,但 production gate 必须把 placeholder 映射到 真实责任人/组和升级路径。

pg36_shop 的当前需求身份

本章 requirements.json 写的是:

service=pg36_shop
data=synthetic teaching only
business owner=placeholder
platform owner=placeholder
target=disposable local Linux sandbox
production approval=false

所以它可以验收部署流程,不能通过真实 pg-ha-standard 的 owner/data gate。

19.1.2 负载形态、增长、峰谷和批处理窗口

“OLTP”不是容量需求

同为 OLTP,可能分别是:

10k tiny point reads/s
500 write transactions/s with 20 indexes
50 large JSON updates/s
100 concurrent long business transactions
bursty checkout traffic
multi-tenant mixed workload

需要一份 workload inventory:

维度
transaction classesbrowse/order/pay/admin
read/write ratio分类别
statements/transaction分布
rows touchedP50/P95/P99
connection behaviorpool、active、idle
latencyP50/P95/P99/timeout
concurrencyarrival、active、parallel
WALbytes/s 与 burst
tempbytes/query 与 aggregate
lockswait、deadlock、long xact
maintenancevacuum/index/backup

第 26 章才正式做容量曲线,本章先确保环境规划有输入。

交易、搜索、空间与分析分开建模

pg36_shop 的四类负载形状:

transactional
  selective, short, latency-sensitive, correctness first

search
  rank/filter, index-heavy, quality + latency

spatiotemporal
  GiST, range, event ingest, retention

analytics
  large scan/aggregate, temp/parallel, freshness-tolerant

如果只用总 QPS,分析扫描和订单写入会互相隐藏。

每类要记录:

endpoint/role
timeout
resource priority
expected concurrency
allowed replica/freshness
degradation
owner

峰值不是日均乘一个系数

峰值来源:

营销活动
整点任务
工资/账单周期
客户端 retry
故障流量转移
缓存失效
批处理重跑
schema migration
backup/checkpoint overlap

真实 peak envelope 至少有:

amplitude
duration
ramp rate
frequency
correlated workloads
recovery tail

一分钟 10 倍峰值与持续 4 小时 3 倍峰值需要不同资源和降级。

流量转移后的单节点峰值

三节点 topology 正常时,读流量可分散;一台 replica 故障后:

[ load_{remaining}

\frac{total\ eligible\ load}{remaining\ eligible\ capacity} ]

若两个 replica 平时各 50%,失去一个后另一个可能接近 100%,也可能 fallback 到 primary。容量必须按 failure state 规划,不只按 happy path。

同理,failover 后:

  • 新 primary 承接全部写;
  • cache 冷;
  • client 重连;
  • replica 重新追赶;
  • backup/maintenance 可能仍在;
  • 旧 primary 需要重建。

增长要分逻辑与物理

逻辑增长:

customers
products
orders/day
items/order
events/day
tenants
retention days

物理增长:

heap
TOAST
indexes
dead tuples/bloat
WAL
temp peak
replicas
backup full/diff/incr
archive retention
monitoring/logs
external projections

一个粗略存储模型:

[ capacity = (heap + toast + indexes + free\ space) \times replica\ factor

  • backup/archive
  • maintenance/upgrade\ headroom ]

不能直接拿业务 CSV 大小乘副本数。

使用增长曲线,不只用线性外推

记录:

daily/weekly sample
seasonality
new feature step changes
largest tenant
retention changes
index additions
compression/archival
confidence interval

容量到达时间:

[ T_{exhaust}

\frac{usable\ capacity - current\ usage - required\ headroom} {growth\ rate} ]

增长率有区间时给出 earliest/expected,而不是一个虚假精确日期。

批处理窗口是一项共享资源预约

批任务包括:

ETL/export
materialized refresh
search/vector rebuild
backup
VACUUM/ANALYZE
index build
partition lifecycle
financial close
data quality reconciliation

每项保存:

字段意义
earliest start / deadline可运行窗口
duration distribution不只平均
CPU/I/O/WAL/temp资源
locks/snapshot并发影响
retry是否会叠加
freshness延迟后果
owner谁停止/恢复
conflict priority与交易冲突时谁让路

“晚上跑”不是窗口。跨时区业务可能没有真正夜间。

维护和业务峰值要画在同一时间轴

建议按 UTC 画一周:

online traffic
batch
backup
checkpoint/WAL archive
autovacuum debt
reporting
deploy
on-call coverage

你可能发现:

业务低谷
  = backup full
  = ETL full scan
  = index maintenance
  = replica lag peak

所谓低谷实际上是数据库最忙时段。

负载可回放性

为了比较环境,保存:

schema/version
data generator or anonymized snapshot identity
query fingerprints
parameter/selectivity distribution
arrival model
connection/pool model
background jobs
warm/cold cache protocol
duration
random seed
success and correctness golden

只保存一条 pgbench -c 100 命令不足以代表业务。

sandbox 的资源结论边界

本章 Vagrant sandbox 要求每台:

>= 2 logical CPUs
>= 2 GiB memory
>= 8 GiB root free
swap = 0

这些只是“足以完成教学部署”的 floor,不是 pg36_shop production sizing。

四台 VM 共享一台 laptop 的:

CPU
memory controller
physical storage
power
hypervisor
host network

因此任何 benchmark 都不能外推生产。

需求表中的 unknown

本章刻意不为以下项目造数字:

production QPS
production data growth
production storage latency
production connection budget
production batch window

它们进入第 24、26、27 章。部署基线的职责是让 unknown 可见,并阻止默认值被 误报为需求。

19.1.3 可用性、RPO、RTO 与维护窗口

四个概念先分开

availability
  服务在测量窗口内按定义成功的比例

RPO
  可接受的数据恢复点损失

RTO
  从场景发生到服务恢复到规定状态的时间

maintenance window
  允许计划变更及其用户影响的时间边界

它们相关,但不能互相替代。

三节点自动 failover 可能有较短可用性中断,却无法恢复昨天误删的数据;一天 一次 full backup 可能可恢复,却不提供当前 primary HA。

先定义成功请求

可用性分母和成功必须明确:

哪些 endpoint
哪些 operation
哪些用户/区域
什么状态码/SQLSTATE
正确性是否计入
延迟阈值
陈旧度阈值
测量位置
计划维护是否排除

如果数据库返回 200/row 但金额错误,不应算可用。

“几个九”换算为时间只是直觉

以 30 天窗口为例:

目标粗略不可用预算
99%7h 12m
99.9%43m 12s
99.95%21m 36s
99.99%4m 19s

真正 SLO 仍由事件型 SLI 计算,不能只用服务器 uptime。

RPO 必须绑定故障场景

示例:

single replica loss       RPO 0
primary failover          async lag within measured policy
sync-confirmed commit     RPO 0 only in modeled sync failure domain
operator DROP             PITR target before error
storage corruption        last verified clean recovery point
region loss               cross-domain repository/standby position

“RPO=0”若没有场景和确认语义,就是不完整承诺。

应用还要知道:

client got success -> commit durability promise
client got timeout -> outcome unknown, must query by idempotency key

RTO 从开始点到结束点

RTO 的起点可能是:

physical failure
monitor detects
alert reaches human
incident declared
recovery decision

终点可能是:

database accepts connections
write service healthy
business golden passes
backlog caught up
all clients restored

如果不定义,两个团队报告的 RTO 可以相差整个检测与验证阶段。

建议分解:

[ RTO = detection

  • decision
  • execution
  • validation
  • traffic\ restoration ]

每段都能优化,也都可能失败。

HA RTO 与 restore RTO 不同

场景路径
primary host lossdetect → elect → promote → route → client retry
database deletedstop damage → choose target → restore → replay → validate
corrupt pagespreserve evidence → classify → restore/rebuild → validate
region lossactivate remote infra → restore/promote → dependencies → DNS

不要用 Patroni failover 的秒数回答整库恢复需要多久。

maintenance 是预算,不是免责

维护窗口应记录:

frequency
duration
notice
allowed impact
rollback deadline
business blackout dates
owner approval
post-check

即使计划维护被 SLO 排除,用户损失仍存在。高成熟度平台会:

  • 滚动维护;
  • 验证连接恢复;
  • 限制每次 blast radius;
  • 保留 rollback;
  • 记录实际中断;
  • 复审窗口是否足够。

升级窗口必须包含回退判断

不只计算安装时间:

preflight
backup/recovery point
traffic drain
package/schema change
restart/failover
application golden
observation
rollback or forward decision

有些 PostgreSQL major upgrade 在数据目录切换后没有简单 rollback;最后可逆 点必须写清。第 30 章专门演练。

服务目标从损失与成本共同推导

目标越强,通常需要:

more independent replicas
synchronous distance/latency trade-off
more recovery copies
more frequent drills
more on-call coverage
more capacity headroom
more change discipline

不能只问“技术上能否做到”,还要问业务是否愿意持续支付,以及组织能否操作。

本章不通过第 20/21 章

第 19 章只验证环境前提:

hosts distinct
versions/initialization uniform
declared and live topology agree
endpoints exist
roles/services active
exceptions explicit

它不注入故障,不执行 failover,不做 restore。因此:

ch20-ha = pending
ch21-backup-restore = pending

sandbox 的准确结论

本章四节点能证明:

one pg-meta member
three pg-test members
one live leader
two live replicas
one offline-query declaration
Pigsty inventory/host/Patroni/SQL facts agree

不能证明:

four production failure domains
production RPO/RTO
production storage durability
production capacity
production secret lifecycle

因为所有 VM 共享物理 laptop,etcd 与 backup target 也各只有一个控制节点。

把例外当结构化结果

requirements.json 固定五项 sandbox exception:

EX19-SHARED-HYPERVISOR
EX19-SINGLE-ETCD
EX19-SINGLE-BACKUP-TARGET
EX19-VIRTUAL-STORAGE
EX19-INVENTORY-SECRETS

通过结果必须写:

sandbox_l2=accepted-with-exceptions
production_ch19_gate=pending

“验收通过”后面没有范围,是一种危险省略。


返回本章目录 · 下一节:计算、内存、存储与网络 · 查看全书目录 · 查看索引中心

最后更新于