PostgreSQL 教程: 使用 Patroni 实现高可用

四月 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 本身不处理法定人数,而是全权委托给其他软件。它兼容 etcdConsulZooKeeper、Kubernetes 四种分布式配置存储(DCS)服务。Patroni 不关心 DCS 部署在哪里、由什么组成,只要能正常读写即可。

这也是架构图中 DCS 作为底层平面支撑所有 PostgreSQL 节点的原因。DCS 可部署在任意位置、使用任意节点数,Patroni 无需管理它。

编排

Patroni 是专为 PostgreSQL 设计的高可用工具,因此它能管理 PostgreSQL 集群的全生命周期操作,包括但不限于:

  • 启动 / 停止 PostgreSQL 服务
  • 提升副本为主节点
  • 初始化新副本
  • 降级主节点
  • 管理日志序列号(LSN)
  • 管理复制槽

Patroni 将所有元数据存入 DCS,并定时更新每个节点的状态。集群始终掌握所有节点信息,包括复制延迟。Patroni 高效工作的核心,是主节点领导令牌机制,工作流程如下:

  1. Patroni 检查当前节点是否持有领导令牌
  2. 持有则刷新令牌,循环检查
  3. 未持有则判断是否可抢占令牌
  4. 可抢占则获取令牌、提升为主节点,循环检查
  5. 不可抢占则作为普通副本,按需配置指向当前主节点

实际流程更复杂,但由于共识层是分布式的,全局只有一个领导令牌。某节点持有令牌时,其他节点无法宣称自己是主节点。Patroni 会根据令牌归属,自动配置所有副本指向当前主节点。如果副本出现重放错误,或曾是旧主节点,Patroni 会通过 pg_rewindpg_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 是其中最好的选择。

了解更多

PostgreSQL 管理