四月 28, 2026
摘要:在本教程中,您将学习到 Patroni 如何为 PostgreSQL 提供高可用性。
目录
Patroni 是做什么的
Patroni 实现了 PostgreSQL 自身尚未具备的能力:构建真正的 PostgreSQL 节点集群。它通过 “HAProxy + DCS” 的三层架构实现这一点,结构如下:
flowchart TB
%% Nodes
HAProxy["HAProxy"]
DCS["DCS"]
subgraph 数据层
%% Nodes
Patroni1["Patroni"]
Patroni2["Patroni"]
Patroni3["Patroni"]
Primary[("主节点")]
Replica1[("副本")]
Replica2[("副本")]
%% Edge connections between nodes
Patroni1 --> Primary
Patroni2 --> Replica1
Patroni3 --> Replica2
end
%% Edge connections between nodes
HAProxy <--> Primary
HAProxy <--> Replica1
HAProxy <--> Replica2
Patroni1 <--> DCS
Patroni2 <--> DCS
Patroni3 <--> DCS
这样将 PostgreSQL 组装为一个自管理的整体系统,Patroni 把所有组件粘合在一起。它是缺失的通信枢纽,记录集群组成、节点状态,并将连接路由到正确位置。下面我们来深入解析它的工作原理。
法定人数(Quorum)
Patroni 最核心的作用,是维护集群法定人数。法定人数的定义很简单:
组织或委员会中,确保事务有效执行所需的最小成员数,通常为多数。
关键在于投票多数,也就是共识。标准计算公式为:N/2 + 1(N 为节点数)。双节点集群需要全部在线才能保持多数,三节点集群则需要 2 个节点在线。正是这个 “额外” 节点,为集群提供了网络故障韧性。当某节点因故障或网络分区失联时,法定人数依然有效,集群持续运行。节点数越多,防护能力通常越强,但受通信开销影响,共识层建议节点数不超过 10 个。
讽刺的是,Patroni 本身不处理法定人数,而是全权委托给其他软件。它兼容 etcd、Consul、ZooKeeper、Kubernetes 四种分布式配置存储(DCS)服务。Patroni 不关心 DCS 部署在哪里、由什么组成,只要能正常读写即可。
这也是架构图中 DCS 作为底层平面支撑所有 PostgreSQL 节点的原因。DCS 可部署在任意位置、使用任意节点数,Patroni 无需管理它。
编排
Patroni 是专为 PostgreSQL 设计的高可用工具,因此它能管理 PostgreSQL 集群的全生命周期操作,包括但不限于:
- 启动 / 停止 PostgreSQL 服务
- 提升副本为主节点
- 初始化新副本
- 降级主节点
- 管理日志序列号(LSN)
- 管理复制槽
Patroni 将所有元数据存入 DCS,并定时更新每个节点的状态。集群始终掌握所有节点信息,包括复制延迟。Patroni 高效工作的核心,是主节点领导令牌机制,工作流程如下:
- Patroni 检查当前节点是否持有领导令牌
- 持有则刷新令牌,循环检查
- 未持有则判断是否可抢占令牌
- 可抢占则获取令牌、提升为主节点,循环检查
- 不可抢占则作为普通副本,按需配置指向当前主节点
实际流程更复杂,但由于共识层是分布式的,全局只有一个领导令牌。某节点持有令牌时,其他节点无法宣称自己是主节点。Patroni 会根据令牌归属,自动配置所有副本指向当前主节点。如果副本出现重放错误,或曾是旧主节点,Patroni 会通过 pg_rewind、pg_basebackup 从当前主节点进行基础备份,或从存档备份恢复,自动重建节点。
这是几乎所有其他高可用工具都不具备的能力。Patroni 不仅会自动提升新主节点,还能重建故障节点。新增节点时,它会根据集群配置自动创建数据目录。DCS 是 Patroni 的唯一可信源,从本质上说,DCS 本身就是集群。
当 DCS 自身故障时,机制会更有趣。
隔离(Fencing)
隔离的核心思想:异常节点必须被下线。原因很简单:失去共识时,任何写入数据都不可信。节点与 DCS 失联、DCS 无响应的原因无关紧要,最安全的做法是停止 PostgreSQL。
如果主节点无法维持领导令牌,其他节点会抢占令牌,Patroni 将其提升为新主节点,集群自动重新配置,服务继续运行。失联的副本无法写入,也无法参与主节点选举。
失联的主节点会感知到新主节点已提升,为避免脑裂,会拒绝写入、停止接收新连接。同理,与 DCS 断开的副本无法被监控,复制延迟持续累积,状态不可信,Patroni 会直接停止该节点的 PostgreSQL 服务。
事实上,大多数 PostgreSQL 高可用方案都缺失这一关键环节。它们几乎都能检测主节点故障并提升副本,但几乎都不考虑故障是网络问题而非节点或 PostgreSQL 本身的场景。在这类系统中,失联节点会继续接收本地写入和已有连接,正常运行,完全不知道集群已完成主节点切换。
失联节点的 PostgreSQL 必须主动终止,这正是 Patroni 的设计核心。与 DCS 失联或 DCS 请求失败,直接关闭服务,简单有效。
注意:集群的一种故障场景是 DCS 自身失去法定人数。例如五节点集群因网络错误分裂为 2 节点和 3 节点两组,2 节点组因失去多数会拒绝运行。受影响节点的 Patroni 无需感知这一点,结果都是停止 PostgreSQL。
路由
Patroni 构建 PostgreSQL 集群的最后一环,是管理连接路由。它通过跟踪领导令牌归属,并提供 HTTP REST 状态接口实现。任何前端路由组件都可查询 Patroni 节点的当前状态:PostgreSQL 是否在线、节点是否可写、复制延迟是否过高等。
路由层通常选用 HAProxy(如架构图所示),也可使用 F5 负载均衡器、AWS ELB 等。路由层决定连接流向哪个节点,或是否允许节点接收连接。用户只需连接路由层,即可访问 PostgreSQL 主节点;若需要连接延迟低于 5MB 的副本,同样通过路由层实现。Patroni 会根据健康检查规则评估并返回状态。
隔离是问题的一半,路由控制是另一半。如果 Patroni 判断节点不可路由,会直接在 REST 接口返回失败。配置正确的路由组件会立即断开已有连接,并拒绝新连接,直到节点恢复正常。
更重要的是,用户和应用无需关心连接到哪个节点,本质上是连接到整个集群。至此,PostgreSQL 才能被准确描述为节点集群。单个节点的运行方式并未改变,但 Patroni 与底层 DCS 构建了粘合所有组件的底层网络。
结语
每个 Postgres 节点都是一个孤岛,作为一个集群,它需要 Patroni 来处理数据节点副本之间的故障切换。没有某种外部协调层,Postgres 根本不是一个自组织的集群。就目前而言,Patroni 是其中最好的选择。