跳至内容
19.5 拓扑、命名与故障域

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 路由 service

etcd 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/nodeOS 实体:物理机、VM 或明确容器边界machine ID、hostname、address
PostgreSQL instance一个 server process + data directory + portmember name、PGDATA、system ID
PostgreSQL database cluster一个 initdb 产生的数据目录及其中 databasessystem identifier
HA cluster / Pigsty pg_cluster一组共享 physical history、可相互接管的 memberspg_cluster、Patroni scope
databasecluster 内的 SQL databaseOID/name/owner/locale
service面向客户端的稳定访问语义name、port、selector、health check
pool连接复用/状态边界PgBouncer endpoint/mode
DCS clusterPatroni 使用的 etcd 共识域etcd membership/quorum
platform deploymentinventory 管理范围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 loss

instance 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 22

cluster 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_shop

pg-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 domain

prod 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-metapg-test 是两个 service unit,不是两个 customer tenant。

业务名与技术名需要映射表

不要让应用团队猜:

业务对象平台对象
pg36_shop servicepg-test teaching service unit
canonical shop DBfuture pg36_shop provisioning target
control/validationpg-meta
OLTP write endpointprimary service contract
analytical readoffline 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-metapg-test 是两个不同 PostgreSQL system identifier;pg-test 有一个 leader 和两个 streaming replica;全部 guest 仍共享一个物理故障域。


上一节:版本与数据库初始化契约 · 返回本章目录 · 下一节:用声明式清单交付两个服务单元 · 查看全书目录 · 查看索引中心

最后更新于