使用 Patroni + etcd + HAProxy 构建自动 failover 集群
PostgreSQL难度: 高级耗时: 2–3 小时构建并运维具备自动 failover 的 PostgreSQL 集群:每个节点上的 PostgreSQL 由 Patroni 管理,leader 选举在 3(或 5)成员的 etcd 中进行,应用通过 HAProxy 的写(5000)和读(5001)端口连接,可选经由 keepalived VIP。除安装外,还提供针对已有集群的运维场景:健康检查、switchover、旧 leader 重新加入、reinit、添加/移除节点、edit-config、pause、Patroni 升级、整体停止/启动、etcd 成员替换以及 etcd 多数派丢失。Patroni 节点上不使用 pg-install 指南(initdb 由 Patroni 自行执行);不使用 Patroni、手动 failover 的 HA 请使用 pg-streaming 指南。
架构: 3 个 PostgreSQL + etcd 节点(共用或独立)+ HAProxy(+ VIP)
场景
- 安装:新建 Patroni 集群 — 从零构建 etcd + Patroni + HAProxy(+ VIP)集群。服务器上不得已有 PostgreSQL 集群:initdb 由 Patroni 执行(不执行 pg-install)。
- 运维 runbook:switchover、failover 测试、维护模式、参数修改 — 在新建集群上依次演练基本操作:状态、switchover、failover 测试(停止 leader,短暂写中断)、维护模式、参数修改。请在维护窗口内执行。
- 集群是否健康?(健康检查) — 只读:角色、延迟、timeline、REST API、etcd 健康、复制槽、待重启及维护模式。
- 计划内 switchover(将 leader 切换到其他节点) — 维护前将 leader 角色受控地切换到某个 replica;写入中断数秒,无数据丢失。
- 发生 failover 后旧 leader 无法重新加入(pg_rewind / reinit) — 崩溃的旧 leader 恢复后应作为 replica 加入;若 pg_rewind 失败,则从 leader 重建数据目录。
- 从零重建 replica(reinit) — replica 已损坏、严重落后或丢失了 WAL:删除其数据目录并从 leader(或备份)重建。leader 不受影响。
- 向集群添加新节点 — 将新节点添加到表单列表末尾:安装软件,在现有节点上更新 pg_hba 和 HAProxy,新节点作为 replica 加入。
- 从集群移除节点 — 永久移除一个 replica 节点:停止 Patroni,清理 DCS 记录和复制槽,并从 HAProxy 中移除。
- 修改 PostgreSQL 或 Patroni 参数(edit-config) — 参数写入 DCS 并应用到所有节点;需要重启的参数执行 restart --pending(先重启 replica)。
- 维护期间停止自动 failover(pause / resume) — pause 状态下 Patroni 不操作 PostgreSQL,也不执行 failover;用于网络/etcd 维护或手动干预。完成后执行 resume。
- 升级 Patroni 软件(滚动) — 集群进入 pause,逐个节点更新并重启 Patroni;PostgreSQL 不停止,不发生 failover。
- 停止 / 启动整个集群(正确顺序) — 计划内整体关闭(存储、数据中心维护):先 replica,再 leader,最后 etcd;启动顺序相反。
- 替换或添加 etcd 成员(etcdctl member) — 移除故障 etcd 成员并添加新服务器(或增加成员数);同步更新 Patroni 的 etcd 主机列表。
- etcd 多数派丢失:leader 变为只读 — etcd 没有 quorum 时,Patroni 会将 leader 设为只读,也不会发生 failover。需恢复 etcd,或从单个成员重建。
开始之前
- PostgreSQL 节点上没有正在运行或之前创建的 PostgreSQL 集群,且 … 为空(集群由 Patroni 自行创建)。这些服务器上未执行 pg-install 指南。
- 所有服务器操作系统版本相同且已更新;时钟已通过 NTP 同步(etcd 和 Patroni 对时钟偏差敏感)。
- PostgreSQL 节点内存为 … GB;… 位于独立磁盘/LV 上,且各节点容量相同。
- etcd 数据(/var/lib/etcd)位于低延迟磁盘(SSD)上。慢速磁盘会干扰 leader 选举;建议不要与 I/O 密集的 PostgreSQL 数据共用磁盘。
- 注意:etcd 节点数为 …(偶数)。偶数不会提高容错能力;请使用 3 或 5。
- 服务器之间可以通过以下端口互访:PostgreSQL …、Patroni REST 8008、etcd 2379/2380、HAProxy 5000/5001/7000…、VRRP(IP 协议 112)…。中间网络设备上也已放行这些规则。
- 服务器可以通过 HTTPS 访问 PGDG 仓库(download.postgresql.org…、apt.postgresql.org…)以及 etcd 所需的 github.com,或已配置内部镜像。
- VIP … 空闲(未在任何服务器上使用),且网络(虚拟化/云)允许 VRRP 以及同一 IP 在服务器间漂移。云环境通常不允许;请改用云负载均衡器。
- 注意:VIP 只有一台 HAProxy 服务器;该服务器宕机时 VIP 无处可漂移。
- 所有服务器上具备 root 或 sudo 权限;维护窗口和回退方案已就绪。
- …:可安装与其他节点相同的操作系统和 PostgreSQL 主版本,… 磁盘容量与其他节点相同,时钟已通过 NTP 同步;到其他节点 …、8008 和 etcd 2379 的访问已放行。
- …(…):低延迟磁盘(SSD),时钟已通过 NTP 同步,已放行来自其他 etcd 成员的 2379/2380 访问和来自 PostgreSQL 节点的 2379 访问;可访问 github.com,或 etcd 归档已放在 /tmp。
指南阶段
- 准备(所有服务器) — 将服务器名称添加到 /etc/hosts · 启用时间同步(chrony) · 内核参数与 THP · 防火墙规则(PostgreSQL 节点) · 防火墙规则(etcd 服务器) · 防火墙规则(HAProxy 服务器)
- etcd 集群 — 安装 etcd 软件 · 安装 etcd 软件 · etcd 配置:… · 创建 etcd systemd 服务 · 创建 etcd systemd 服务 · 启动 etcd(在所有 etcd 节点上同时进行) …
- PostgreSQL 与 Patroni 软件 — 添加 PGDG 仓库 · 添加 PGDG 仓库 · 安装 PostgreSQL 和 Patroni · 禁用独立的 PostgreSQL 服务并准备目录
- Patroni 配置 — 将密码写入环境文件 · 将环境文件挂接到 Patroni 服务 · patroni.yml:… · 校验配置
- 启动集群 — 在第一个节点上启动 Patroni · 在其他节点上启动 Patroni:… · 检查集群状态
- HAProxy — 安装 HAProxy · 安装 HAProxy · 编写 haproxy.cfg · 编写 haproxy.cfg · 校验并启动 HAProxy · 校验并启动 HAProxy
- 使用 keepalived 的 VIP — 安装 keepalived · 安装 keepalived · keepalived 配置:… · 启动 keepalived · 启动 keepalived
- 应用用户与连接测试 — 应用用户与数据库 · 设置应用用户密码 · 检查 REST API 健康检查端点 · 通过 HAProxy 测试连接 · 应用连接字符串
- 安装后 — 创建 etcd snapshot 备份 · 创建 etcd snapshot 备份 · 配置备份(必需) · 接入监控
- 集群状态 — 成员、角色与延迟
- 计划内 switchover — 执行 switchover
- Failover 测试(停止 leader) — 在 leader 节点上停止 Patroni · 观察新 leader · 重新启动旧 leader
- 维护模式(pause) — 将集群置于维护模式 · 执行维护 · 退出维护模式
- 参数修改 — 在整个集群范围内修改参数 · 应用待重启的变更
- 健康检查(只读) — 成员、角色、timeline 与延迟 · 最近的 leader 变化(history) · REST API 健康端点 · etcd 健康 · 复制延迟、复制槽与待重启(在 leader 上) · 配置与维护模式
- 计划内 switchover — Switchover 前检查 · 执行 switchover · 验证新 leader 及旧 leader 重新加入
- 维护模式(pause / resume) — Pause 前检查 · 将集群置于维护模式(pause) · 执行维护 · 退出维护模式(resume)
- Patroni 升级:准备 — 当前与目标 Patroni 版本 · 备份并校验配置 · 将集群置于维护模式(pause)
- Patroni 升级:收尾 — 退出维护模式(resume)
- 停止集群(replica → leader → etcd) — 记录状态和角色 · 停止应用 · 在 replica 上停止 Patroni · 在 leader 上停止 Patroni · 停止 etcd
- 启动集群(etcd → 最后的 leader → replica) — 启动 etcd(在所有 etcd 成员上同时进行) · 验证 etcd 健康 · 先在最后的 leader 上启动 Patroni · 在 replica 上启动 Patroni · 验证集群并启动应用
- 诊断:etcd 多数派丢失 — 确认症状:没有 leader,PostgreSQL 只读 · 查看 etcd 成员状态
- 路径 A:恢复 etcd 成员 — 路径 A:启动 etcd 服务 · 确认 Patroni 已恢复
- 验证与预防 — 验证 etcd 和 Patroni,评估 failsafe