









问题现象:3节点的Patroni + PostgreSQL集群 postgresql-0 节点异常,一直处于starting状态,Lag in MB 显示 unknown,postgresql-0使用的pv、etcd集群排查都没有问题,集群状态及日志报错如下图所示,输出排查步骤及恢复方案
基于您提供的截图和描述,这是一个典型的 Patroni + PostgreSQL 集群中备库(Replica)启动失败/卡住 的问题。
状态异常:postgresql-0 节点在 patronictl list 中显示为 starting,且 Lag in MB 为 unknown。这意味着 Patroni 无法成功连接到该节点的 PostgreSQL 进程来查询复制延迟。
日志关键信息(第二张图):
Still starting up as a standby.:Patroni 认为 PG 正在作为备库启动。
Error communicating with PostgreSQL... /var/run/postgresql:5432 - rejecting connections:这是核心错误。PostgreSQL 进程虽然可能启动了,但它处于“拒绝连接”的状态。通常发生在 PG 正在进行崩溃恢复(Crash Recovery)、正在重放 WAL 日志尚未达到一致性状态,或者启动过程中卡住了。
Failed to determine PostgreSQL state from the connection:因为连不上数据库,Patroni 无法判断其真实状态,只能回退到缓存的角色信息。
拓扑结构:postgresql-2 是 Leader (TL 266),postgresql-1 是健康的 Replica (TL 135, Lag 752MB),postgresql-0 是故障节点。
手动连接报错:FATAL: the database system is starting up。这证实了 PostgreSQL 进程确实活着,但它还没有完成启动/恢复过程,因此拒绝任何业务连接。这也是为什么 Patroni 报 rejecting connections 和 Lag in MB: unknown 的根本原因。
进程状态 (ps -ef):
PID 61 是主进程 postgres -D ...。
关键进程 PID 64:postgresql: startup recovering 00000008E000000000000077。
结论:您的 postgresql-0 节点当前正处于 WAL 日志回放(Crash Recovery / Standby Recovery)阶段。它正在努力应用 WAL 日志以达到一致性状态。在 startup 进程完成之前,数据库无法接受连接,Patroni 也就只能一直显示 starting。
结合您第一张图的信息:
集群整体延迟大:健康的备库 postgresql-1 也有 752 MB 的延迟。这说明主库写入量很大,或者网络/磁盘 IO 存在瓶颈。
Timeline (TL) 差异巨大:Leader (postgresql-2) 的 TL 是 266,而 postgresql-1 的 TL 是 135。这说明集群历史上发生过非常多次的故障切换(Failover)。
当前恢复位置:postgresql-0 正在恢复的 WAL 段是 00000008E000000000000077(注意前缀 00000008 代表 Timeline 8)。
核心矛盾:postgresql-0 本地的数据还停留在非常古老的 Timeline 8,而当前的 Leader 已经在 Timeline 266 上了。
PostgreSQL 备库在启动时,必须先从本地 WAL 或归档中把历史日志回放完,直到追上当前的 Timeline。由于跨度太大(从 8 到 266),它可能需要回放海量的 WAL 日志,或者正在尝试寻找跨越这些 Timeline 的历史记录,导致启动过程极其漫长,看起来像是“卡住”了。
请按顺序在 postgresql-0 (172.24.0.107) 节点上执行以下操作:
Patroni 的日志只告诉我们“连不上”,PG 自己的日志才会告诉我们“为什么连不上”。
# 找到 PG 日志路径,通常在 /var/log/postgresql/ 或数据目录下的 pg_log/ # 如果是容器化部署,使用 kubectl logs 或 docker logs tail -f /var/log/postgresql/postgresql-*.log # 或者 tail -f /home/postgres/data/pg_log/postgresql-*.log
重点关注日志中的以下关键词:
redo starts at ... / redo done:看是否在进行恢复。如果一直卡在 redo starts 且没有进度,说明 WAL 回放有问题。
could not connect to the primary server:看是否能连通 Leader (172.24.0.116)。
FATAL 或 PANIC:任何致命错误。
waiting for WAL to become available:等待 WAL 日志。
确认 PG 进程是否存在,以及处于什么状态。
ps -ef | grep postgres
如果没有 postgres 进程:说明 PG 根本没起来,或者是被 Patroni 反复重启。
如果有进程,但状态是 D (不可中断睡眠) 或 R (运行中) 且 CPU 占用高:可能正在大量回放 WAL。
检查是否有残留的 postmaster.pid:
ls -l /home/postgres/data/postmaster.pid # 路径根据实际情况调整
注意:不要随意删除此文件,除非你确定 PG 进程已经完全不存在。
尝试直接用 pg_isready 或 psql 连接本地 socket,看具体报错。
# 检查端口是否监听 netstat -tlnp | grep 5432 # 尝试本地连接 su - postgres psql -h /var/run/postgresql -p 5432 -U postgres -c "select 1;"
如果报错 the database system is starting up:证实了日志中的猜测,PG 还在恢复中,需要等待。
如果报错 no pg_hba.conf entry:配置问题。
如果连接直接被拒绝且无进程:PG 启动失败。
确保 postgresql-0 能访问 Leader (postgresql-2, 172.24.0.116) 的 5432 端口。
telnet 172.24.0.116 5432 # 或 nc -zv 172.24.0.116 5432
如果不通,检查防火墙、安全组或 K8s NetworkPolicy。
根据上述排查结果,选择对应的方案:
如果 PG 日志显示正在 redo 且没有报错,只是速度慢(特别是看到 pg-1 也有 700多MB 延迟,说明集群整体写入压力大或网络带宽受限):
耐心等待:不要强制重启。让 PG 完成恢复。
监控进度:观察日志中 LSN 的变化。
优化:如果长期如此,考虑增加 max_wal_senders,调整 wal_receiver_status_interval,或检查磁盘 IO 性能。
如果日志显示 PANIC,或者长时间(超过 30 分钟)无任何进展,且 psql 始终报 starting up,则需要重建该副本。由于是 Patroni 集群,重建非常安全。
针对这种情况,有两种处理策略。强烈建议直接采用方案 B,因为等待一个跨越 200 多个 Timeline 的备库自行追平几乎是不现实的,且极易出错。
如果您刚刚重启该节点不到 10-20 分钟,可以观察一下 PostgreSQL 的原生日志,看 LSN 是否在跳动。
# 查看 PG 日志,确认是否在持续回放 tail -f /home/postgres/pgdata/pgroot/data/log/*.log # (路径根据您的实际 pg_log 位置调整)
如果日志里不断有 redo at ... 且数字在变大,说明它在干活。但考虑到 TL 差距,不建议死等。
既然 PV 和 etcd 都没问题,利用 Patroni 的自动克隆功能,让它直接从当前的 Leader (postgresql-2) 重新全量同步一份最新的数据,是解决此问题的标准做法。
操作步骤:
1.停止 Patroni 服务
为了防止 Patroni 在我们清理数据时反复尝试拉起 PG,先停掉它。
# 如果是 systemd 管理 systemctl stop patroni # 如果是容器环境 (如 K8s/Docker),请通过编排工具停止该 Pod/Container
2.确认并清理数据目录
从截图中可以看到,您的数据目录是:/home/postgres/pgdata/pgroot/data。
警告:请务必核对路径,删除错误目录会导致灾难性后果!
# 再次确认路径 ls -ld /home/postgres/pgdata/pgroot/data # 清空该目录下的所有内容 (保留目录本身) rm -rf /home/postgres/pgdata/pgroot/data/* # 确认已清空 ls -A /home/postgres/pgdata/pgroot/data
3.重新启动 Patroni
systemctl start patroni # 或启动对应的容器/Pod
4.观察重建进度
Patroni 启动后,会发现数据目录为空,自动触发 pg_basebackup 从 Leader (172.24.0.116) 克隆数据。
查看 Patroni 日志:
tail -f /var/log/patroni/patroni.log # 或 journalctl -u patroni -f
您应该会看到类似 replicating from leader、running pg_basebackup 的日志。
查看集群状态:
patronictl list
状态变化预期:
starting (正在克隆)
running (克隆完成,开始流复制)
Lag in MB 会从 unknown 变成一个具体的数字,并逐渐减小到 0 或很小的值。
TL (Timeline) 会变成 266,与 Leader 一致。
您遇到的不是故障,而是备库数据太旧,正在艰难地进行跨 Timeline 恢复。由于落后太多(TL 8 vs TL 266),自行恢复效率极低。清空数据目录让 Patroni 重新克隆是解决此问题的最佳实践。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。