19.5 拓扑、命名与故障域
三台服务器不是高可用拓扑,除非我们知道三台分别会因什么而一起失败。 “主库、从库、VIP”也不是足够精确的词表,尤其在 promotion 之后。
19.5.1 主节点、同步副本、异步副本与仲裁
primary 是当前角色,不是机器身份
PostgreSQL physical replication 中:
primary 接受写入并生成 WAL
standby 持续恢复并接收/重放 WAL
hot standby 在恢复中提供只读查询promotion 后,原 standby 可以成为 primary。于是:
pg-test-1 = stable member identity
primary = mutable runtime role把 hostname 叫 prod-primary 会在第一次切换后撒谎。
原生证据:
SELECT pg_is_in_recovery();false -> 当前可写 primary 形态
true -> 当前处于 recovery 的 standby它不单独证明 service routing 正确,也不证明另一台没有同时可写。
physical standby 重放同一条 WAL 历史
同一 cluster 的成员应共享:
system identifier
compatible major/build/storage layout
timeline ancestry
WAL history
tablespace paths
extension binary prerequisites官方 Log-Shipping Standby 强调 primary/standby 应尽量相似,physical log shipping 不跨 major。
本章用 system identifier 检查:
pg-test-1 == pg-test-2 == pg-test-3
pg-meta != pg-test异步复制的 commit 不等待副本
streaming replication 默认异步。正常低延迟不等于零 RPO:
client receives commit
WAL may still be in primary-only failure domain
primary suffers unrecoverable loss
promotion candidate lacks last records数据损失窗口由故障时实际 receive/write/flush/replay 位置决定,而不是 平时 dashboard 上“通常 0 MB”决定。
观察 primary:
SELECT application_name,
client_addr,
state,
sync_state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_gap_bytes
FROM pg_stat_replication
ORDER BY application_name;本章只确认 replica 在 streaming;第 20 章才测 failure-time 数据包络。
同步复制把一部分 commit latency 换成确认
PostgreSQL synchronous replication 可以让 commit 等待一个或多个 standby 反馈。等待层次包括:
remote_write
on / remote flush
remote_apply它们不是同义词。remote_apply 还等待 replay 可见,延迟与阻塞代价更高。
配置又分:
FIRST n (...) priority-based
ANY n (...) quorum-based同步复制只有在以下条件下才提供期望保护:
- standby 是真实独立故障域;
- storage flush 语义可信;
- synchronous standby 处于 streaming;
- application 没有降级为更弱
synchronous_commit; - 超时/降级策略符合业务选择;
- 失联时是停止写还是降级继续写已经定义。
“有 sync replica”不能省略这些条件。
同步复制也可能让写入不可用
若要求一个同步确认,而没有任何合格 standby:
transaction does work
commit waits
locks may remain held
application timeout/retry
load amplifies因此 RPO 与 availability 之间要由 owner 选择:
fail closed: wait, preserve durability target
degrade: resume async, accept explicit data-loss risk自动降级如果没有审计,就是悄悄改变服务合同。
“仲裁”不要与数据副本混淆
PostgreSQL core 没有一个保存业务数据的“仲裁节点”概念。Pigsty 的 HA 参考实现里:
Patroni 管理成员状态、leader lock 与操作
etcd 提供分布式配置存储/共识
PostgreSQL members 保存业务数据/WAL
HAProxy 依据 health checks 路由 serviceetcd member:
- 不保存可 promotion 的 PostgreSQL data;
- 不确认每个业务 transaction 已持久化;
- 不替代 backup;
- 不依据最新 WAL 自动解决所有数据选择;
- 需要自己的 quorum 与 failure domains。
把一个 etcd 节点叫“第三票”,然后声称两台 PostgreSQL 已实现零数据丢失, 是错误模型。
DCS quorum 与数据库成员数分别计算
三节点 PostgreSQL + 单节点 etcd:
database copies = 3
DCS members = 1
shared laptop = 1三个数字不能互相抵消。单 etcd failure 会影响自动 HA 控制面;同一 laptop failure 会同时失去全部 VM。
本章正式沙箱把这两项登记为:
EX19-SINGLE-ETCD
EX19-SHARED-HYPERVISOR所以它适合练拓扑与协议,不适合宣称 production availability。
offline replica 是 workload placement
Pigsty 支持专门的 offline instance,也支持在已有 replica 上设置
pg_offline_query: true,把它纳入 offline service。官方
Cluster / Instance
明确说明后一种是资源折中。
本章:
10.10.10.13:
pg_role: replica
pg_offline_query: true它仍是同一 pg-test physical replica,不是独立 analytical authority。
标记不自动限制 CPU/I/O,也不自动阻止用户绕过 service 直连。第 17、22、
26、30 章分别处理分析语义、服务接入、容量和资源治理。
本章拓扑不是第 20 章结论
本章可以证明:
one Patroni leader
two streaming replicas
SQL recovery roles agree
declared endpoints reachable不能证明:
leader loss detection time
fencing
split-brain exclusion
automatic failover RTO
failure-time RPO
client reconnection semantics
old primary rejoin safety这些必须用受控 fault drill 取得。
19.5.2 节点、实例、集群、服务的统一词表
同一个“集群”常指四种东西
先建立词表:
| 词 | 本书定义 | 稳定身份/证据 |
|---|---|---|
| host/node | OS 实体:物理机、VM 或明确容器边界 | machine ID、hostname、address |
| PostgreSQL instance | 一个 server process + data directory + port | member name、PGDATA、system ID |
| PostgreSQL database cluster | 一个 initdb 产生的数据目录及其中 databases | system identifier |
HA cluster / Pigsty pg_cluster | 一组共享 physical history、可相互接管的 members | pg_cluster、Patroni scope |
| database | cluster 内的 SQL database | OID/name/owner/locale |
| service | 面向客户端的稳定访问语义 | name、port、selector、health check |
| pool | 连接复用/状态边界 | PgBouncer endpoint/mode |
| DCS cluster | Patroni 使用的 etcd 共识域 | etcd membership/quorum |
| platform deployment | inventory 管理范围 | exact inventory/release |
PostgreSQL 官方把一个 data directory 称为 database cluster;平台团队又常把 一个 HA group 称 cluster。文档必须说明上下文。
node 不等于 instance
一台 node 可以运行:
PostgreSQL instance
PgBouncer
HAProxy
Patroni
exporters/Vector
infra components
多个独立实例(若平台允许)一个 PostgreSQL cluster 也可以跨多 node。
“node down”与“Postgres down”故障面不同:
process crash
OS crash
VM pause
host failure
rack/zone loss
network partition
storage loss
control-plane lossinstance identity 不能只用 IP
IP 可以复用,DNS 可以漂移,hostname 可以被自动化改写。本章组合:
declared address
post-convergence hostname
hash(machine-id)
Patroni member name
PostgreSQL system identifier
pg_cluster
pg_seq实验中发现一个真实陷阱:工作站 ~/.ssh/config 将四个地址映射到本机不同
转发规则,最初所有连接看起来都是 meta。正式采集强制:
ssh -F /dev/null ...再验证四个不同 machine ID。连接成功不是目标身份成功。
service 是语义,不是 socket
Pigsty 默认 service 可能包括:
5433 primary
5434 replica
5436 primary direct
5438 offline官方 Service/Access 记录这些默认映射。端口能建立 TCP 只证明 listener/reachability,不证明:
- primary service 一定落在 current primary;
- replica service 的 freshness;
- pool transaction/session 语义;
- role/database/HBA 正确;
- TLS hostname 验证;
- failover 后客户端恢复。
所以本章 endpoint probe 的解释字段明确写:
reachability and Patroni identity only
routing/pooling/failover/saturation belong to chapter 22cluster name 不应含 current role
推荐稳定层次:
service unit pg-test
member pg-test-1 / pg-test-2 / pg-test-3
runtime role primary / replica
service pg-test-primary / pg-test-replica / pg-test-offline
database test
application pg36_shoppg-test-primary 可以是 service 名,不应是固定 machine 名。
数据库里的 role 又是另一种 role
避免一句“role 是 replica”同时指:
Pigsty member role pg_role
Patroni runtime role Leader/Replica
PostgreSQL recovery role pg_is_in_recovery
SQL authorization role pg_roles
business owner role human/team responsibility表格、变量名和 evidence 都写全称。
声明角色与观察角色都要保存
inventory 声明:
10.10.10.11: { pg_seq: 1, pg_role: primary }
10.10.10.12: { pg_seq: 2, pg_role: replica }
10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true }观察:
Patroni leader/replica + state
SQL in_recovery
service health identity第一次部署时二者应一致。发生 failover 后,inventory 的 bootstrap role 不应 被天真解释为永恒运行角色;第 20 章会定义 drift 语义。
19.5.3 环境、区域、租户与业务命名
命名要编码稳定属性
适合进入名字的:
environment
service/business domain
service unit
region/site
sequence不适合进入固定 host 名的:
current primary
healthy
latest
temporary owner
current version
current ticket稳定属性让名字在 role change 后继续真实。
一份可扩展命名模型
示例:
platform deployment shop-prod-cn1
service unit pg-shop-order
members pg-shop-order-1..3
database shop
NOLOGIN owner shop_owner
runtime login shop_app
services pg-shop-order-primary
pg-shop-order-replica
pg-shop-order-offline名字要满足:
- PostgreSQL identifier 限制;
- DNS label 限制;
- metric label cardinality;
- certificate SAN;
- log/search 可读性;
- automation group syntax;
- rename cost。
environment 是权限与数据边界
常见:
dev
test
staging
prod
dr不能只靠名字隔离。还要有:
account/project
network
credentials/CA
backup repository
monitoring tenant
data policy
change authority
failure domainprod database 和 test database 放在同一个 cluster,通常仍共享 superuser、
WAL、storage、restart、capacity 和 incident blast radius。
region、zone、rack 必须对应可验证故障域
一个 label az-a 不等于独立 zone。登记:
provider/site ID
building/room/rack
power feed
top-of-rack/core network
hypervisor/host group
storage controller/array/replication
DNS/NTP/KMS/CA
DCS and backup dependencies然后为每个 component 画依赖。相同依赖会形成 correlated failure。
本章四台 VM:
four machine IDs
one physical Mac
one hypervisor
one power source
one storage substrate所以 failure-domain count 不是四。
tenant 边界不等于 schema 名
租户可能通过:
row
schema
database
cluster
account/project隔离强度逐步变化,成本也变化。命名中加入 tenant 前,先定义:
- authentication/authorization;
- noisy-neighbor;
- backup/restore granularity;
- key ownership;
- data residency;
- deletion;
- metrics/audit;
- exit/migration。
本章 pg-meta 与 pg-test 是两个 service unit,不是两个 customer tenant。
业务名与技术名需要映射表
不要让应用团队猜:
| 业务对象 | 平台对象 |
|---|---|
| pg36_shop service | pg-test teaching service unit |
| canonical shop DB | future pg36_shop provisioning target |
| control/validation | pg-meta |
| OLTP write endpoint | primary service contract |
| analytical read | offline service contract |
正式 inventory 当前还会创建 template 自带的 test/meta database。它们是
部署示范对象,不表示上卷的 pg36_shop fixture 已迁入这个下卷沙箱。
name registry 要防冲突与复用
登记:
name
type
immutable ID
environment
owner
created/retired
aliases
DNS/certificate names
monitoring labels
backup stanza
reuse quarantine立即复用已退役 cluster 名可能让:
- old DNS/cache 指向新服务;
- backup stanza 混淆;
- monitoring time series 串联;
- client secret 意外生效;
- automation limit 选错目标。
本章拓扑清单
topology.mmd 表达:
10.10.10.10 pg-meta-1 pg-meta primary + infra/etcd/MinIO
10.10.10.11 pg-test-1 pg-test primary
10.10.10.12 pg-test-2 pg-test replica
10.10.10.13 pg-test-3 pg-test replica + offline query它同时画出共享 hypervisor。架构图若只画 database arrows、隐藏共同依赖, 会高估 availability。
命名与拓扑验收
validator 交叉检查:
address -> expected post-deployment hostname
address -> distinct machine ID hash
address -> inventory pg_cluster/pg_role/offline
address -> SQL cluster_name/in_recovery/system ID
cluster -> Patroni host/role/state反例:
reuse-one-machine-identity -> E_HOST_IDENTITY
declare-two-live-leaders -> E_TOPOLOGY通过后的精确结论:
四个地址对应四个同构 Linux guest;
pg-meta与pg-test是两个不同 PostgreSQL system identifier;pg-test有一个 leader 和两个 streaming replica;全部 guest 仍共享一个物理故障域。
上一节:版本与数据库初始化契约 · 返回本章目录 · 下一节:用声明式清单交付两个服务单元 · 查看全书目录 · 查看索引中心