从原生 PG 到 Vastbase、GaussDB:聊透"Patroni + ETCD"高可用架构演进与实战
昨天我们介绍了 PostgreSQL 的一主两从搭建过程,并详细说明了 synchronous_standby_names 参数在 ANY、FIRST等不同配置下的同步差异,尽管可以保障数据冗余,但无法提供高可用自动切换能力。因此,本期我们将手把手搭建 PG + Patroni + ETCD 的高可用容灾集群,并梳理 Patroni 的常用运维操作。
值得一提的是,这套经典架构被广泛借鉴与演进:
- 海量数据
Vastbase G100:在 HAS1.2 高可用服务中,DCS 对标ETCD、HAS 对标Patroni。演进至 HAS 3.0 后,进一步支持了资源池化共享存储,实现基于共享存储 (如前天提到的 Logger + Dorado 方案)的双机单活架构。 GaussDB集中式:- 常规模式 下,CM 组件(CM Agent + CM Server + OM Monitor)借助
ETCD存储拓扑并参与选主仲裁,实现故障切换; - DCF模式 下,
GaussDB集中式集群无需部署独立的ETCD组件,改用内嵌于 CM 的 DCC(基于 DCFPaxos构建的 KV 状态机) 承接集群拓扑与配置存储; DN 节点选主则由 DCF 基于Paxos协议自治完成(XLOG 与 DCF 日志合一),完全脱离了对外部ETCD的依赖。
- 常规模式 下,CM 组件(CM Agent + CM Server + OM Monitor)借助
简单说就是:Patroni 是"外挂式 HA"------数据库不懂选主,靠外部 ETCD + Patroni 指挥;GaussDB 是"内核级 HA"------数据库自己通过 DCF 投票选主,CM 仅做辅助管理。
1. 环境准备
1.1 节点规划
| 主机名 | 网卡 | IP地址 | 安装软件 | 角色作用 |
|---|---|---|---|---|
| pgsql1 | ens33 | 192.168.182.146 | PostgreSQL/ETCD/Patroni |
主库 |
| pgsql2 | ens33 | 192.168.182.147 | PostgreSQL/ETCD/Patroni |
从库1 |
| pgsql3 | ens33 | 192.168.182.148 | PostgreSQL/ETCD/Patroni |
从库2 |
记得预留同网段未被使用的地址作为 VIP(本文使用 192.168.182.194),主从切换后,避免在应用中修改数据库连接信息。
1.2 设置主机名
shell
hostnamectl set-hostname pgsql1
hostnamectl set-hostname pgsql2
hostnamectl set-hostname pgsql3
1.3 配置 hosts 文件
shell
cat >> /etc/hosts <<EOF
192.168.182.146 pgsql1
192.168.182.147 pgsql2
192.168.182.148 pgsql3
EOF
1.4 关闭防火墙和SELIUNIX
shell
systemctl status firewalld
systemctl stop firewalld
systemctl disable firewalld
systemctl status firewalld
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
1.5 创建 postgres 用户
shell
useradd postgres
echo 'postgres' | passwd --stdin postgres
1.6 配置资源限制
shell
cat >> /etc/security/limits.conf <<EOF
postgres soft nproc unlimited
postgres hard nproc unlimited
postgres soft nofile 100000
postgres hard nofile 100000
postgres soft stack unlimited
postgres hard stack unlimited
postgres soft core unlimited
postgres hard core unlimited
postgres soft memlock unlimited
postgres hard memlock unlimited
EOF
1.7 创建数据目录
shell
rm -rf /var/lib/etcd/*
rm -rf /data/*
mkdir -p /pgsql/{pghome,patroni}
mkdir -p /data/{pgwal,pgdata,pgbak}
mkdir -p /data/pgwal/archive_wals
mkdir -p /data/pgdata/pg13
chown -R postgres:postgres /pgsql
chown -R postgres:postgres /data/
chmod -R 700 /pgsql
chmod -R 700 /data/{pgwal,pgdata,pgbak}
1.8 配置环境变量
shell
su - postgres
cat >> /home/postgres/.bash_profile <<EOF
export PGHOME=/pg/pghome
export PGDATA=/data/pgdata/pg13
export PGPORT=5432
export PGDATABASE=postgres
export LD_LIBRARY_PATH=\$PGHOME/lib:\$LD_LIBRARY_PATH
export PATH=\$PGHOME/bin:\$PATH
EOF
1.9 配置 yum 源 && 安装依赖包
shell
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum -y install wget gcc gcc-c++ epel-release llvm5.0 llvm5.0-devel clang libicu-devel perl-ExtUtils-Embed readline readline-devel zlib zlib-devel openssl openssl-devel pam-devel libxml2-devel libxslt-devel openldap-devel systemd-devel tcl-devel python-devel
1.10 配置 sudo 权限
shell
echo "postgres ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers > /dev/null
cat /etc/sudoers
2. 搭建 ETCD 集群
2.1 安装 ETCD
shell
yum -y install etcd
2.2 配置 etcd.conf
2.2.1 节点一配置
shell
cat > /etc/etcd/etcd.conf << EOF
ETCD_NAME="etcd1"
ETCD_DATA_DIR="/var/lib/etcd/etcd1"
ETCD_LISTEN_PEER_URLS="http://192.168.182.146:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://192.168.182.146:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.182.146:2380"
ETCD_INITIAL_CLUSTER="etcd1=http://192.168.182.146:2380,etcd2=http://192.168.182.147:2380,etcd3=http://192.168.182.148:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.182.146:2379"
EOF
参数说明:
ETCD_NAME:节点名称,三个节点不同即可;ETCD_DATA_DIR:数据目录;ETCD_LISTEN_PEER_URLS:监听用于节点之间通信的url,可监听多个,集群内部将通过这些url进行数据交互(如选举,数据同步等);ETCD_LISTEN_CLIENT_URLS:监听客户端请求的地址列表url,可以监听多个,多个用逗号分割,或者写成0.0.0.0,监听所有请求地址;ETCD_INITIAL_ADVERTISE_PEER_URLS:用于节点之间通信的url,节点间将以该值进行通信;ETCD_INITIAL_CLUSTER:集群中所有的 ETCD_INITIAL_ADVERTISE_PEER_URLS 的合集。etcd启动的时候,通过这个配置找到其他etcd节点的列表;ETCD_INITIAL_CLUSTER_STATE:初始化的时候,集群的状态:new 和 existing 两种状态。new代表新建的集群,existing 代表加入已经存在的集群;ETCD_INITIAL_CLUSTER_TOKEN:节点的 token 值,设置该值后集群将生成唯一 id,并为每个节点也生成唯一 id,当使用相同配置文件再启动一个集群时,只要该 token 值不一样,etcd集群就不会相互影响。ETCD_ADVERTISE_CLIENT_URLS:监听使用的客户端通信 url,该值用于 etcd 代理或 etcd 成员与 etcd 节点通信;
2.2.2 节点二配置
shell
cat > /etc/etcd/etcd.conf << EOF
ETCD_NAME="etcd2"
ETCD_DATA_DIR="/var/lib/etcd/etcd2"
ETCD_LISTEN_PEER_URLS="http://192.168.182.147:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://192.168.182.147:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.182.147:2380"
ETCD_INITIAL_CLUSTER="etcd2=http://192.168.182.146:2380,etcd2=http://192.168.182.147:2380,etcd3=http://192.168.182.148:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.182.147:2379"
EOF
2.2.3 节点三配置
shell
cat > /etc/etcd/etcd.conf << EOF
ETCD_NAME="etcd3"
ETCD_DATA_DIR="/var/lib/etcd/etcd3"
ETCD_LISTEN_PEER_URLS="http://192.168.182.148:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://192.168.182.148:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.182.148:2380"
ETCD_INITIAL_CLUSTER="etcd1=http://192.168.182.146:2380,etcd2=http://192.168.182.147:2380,etcd3=http://192.168.182.148:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.182.148:2379"
EOF
2.3 启动 ETCD 服务
shell
systemctl start etcd
systemctl enable etcd
systemctl status etcd
说明:如果采用解压安装,配置文件相同,启动时指定配置文件。
2.4 ETCD 常用命令
- 查看集群成员
shell
[root@pgsql1 ~]# etcdctl member list
2f15f40d77f8d42d: name=etcd3 peerURLs=http://192.168.182.148:2380 clientURLs=http://192.168.182.148:2379 isLeader=false
2f4bc9f71dcea29c: name=etcd1 peerURLs=http://192.168.182.146:2380 clientURLs=http://192.168.182.146:2379 isLeader=true
a0285e8acbd01911: name=etcd2 peerURLs=http://192.168.182.147:2380 clientURLs=http://192.168.182.147:2379 isLeader=false
- 查看目录
shell
[root@pgsql1 ~]# etcdctl ls /pgsql/
/pgsql/PGCluster
3、 获取键值对
shell
[root@pgsql1 ~]# etcdctl get /pgsql/PGCluster/members/pgsql1
{"conn_url":"postgres://192.168.182.146:5432/postgres","api_url":"http://192.168.182.146:8008/patroni","state":"running","role":"replica","version":"4.1.0","xlog_location":1207960128,"replay_lsn":1207960128,"receive_lsn":1207960128,"replication_state":"streaming","timeline":54}
3. 安装 PostgreSQL
shell
tar -zxvf postgresql-13.4.tar.gz
cd postgresql-13.4
./configure --prefix=/pgsql/pghome
gmake world
gmake install
cd contrib
make && make instal
4. 在线安装 patroni
4.1 安装 python3
bash
yum install -y python3
[root@pgsql3 ~]# rpm -qa |grep python3
python3-pip-9.0.3-8.el7.noarch
python3-3.6.8-21.el7_9.x86_64
python3-libs-3.6.8-21.el7_9.x86_64
python3-setuptools-39.2.0-10.el7.noarch
4.2 安装 pip
shell
curl https://bootstrap.pypa.io/pip/3.6/get-pip.py -o get-pip.py
python3 get-pip.py
下载过程:

4.3 安装 Patroni
shell
pip install psycopg2-binary -i https://mirrors.aliyun.com/pypi/simple/
pip install patroni[etcd] -i https://mirrors.aliyun.com/pypi/simple/
注:使用 root 用户 pip 安装的包会在以下目录,可以单独创建 python 虚拟目录:python3 -m venv /pgsql/patroni/patroni-venv

4.4 验证 Patroni 安装成功
shell
patroni --version
4.5 配置 Patroni 的 YAML 文件
Patroni支持三种同步复制模式:
- 标准同步模式 (synchronous_mode: true)
- 严格同步模式 (synchronous_mode_strict: true)
- 仲裁提交模式 (synchronous_mode: "quorum")
| 模式类型 | 参数配置 | 核心工作机制 | 适用场景与风险 |
|---|---|---|---|
| 标准同步模式 | synchronous_mode: true |
Patroni 自动将健康备库更新进 synchronous_standby_names。当同步备库故障时,Patroni 会自动将同步模式降级或切换到其他可用备库。 |
兼顾可用性与 RPO 。若所有备库挂掉,Patroni 会降级为异步,保证主库不卡死,但可能丢失少量未同步的数据。 |
| 严格同步模式 | synchronous_mode_strict: true |
强制保持同步约束(RPO=0)。如果集群中没有可用的同步备库,主库将拒绝写入,直到至少有一个同步备库恢复正常。 | 强一致性场景(如金融核心结算)。风险在于备库全挂或网络分区时,主库会失去写能力,牺牲高可用性(RTO)来保证数据零丢失。 |
| 仲裁提交模式 | synchronous_mode: "quorum" |
结合 ANY N (standby1, standby2...) 语法,采用法定人数(Quorum)机制,只要达到指定数量的备库确认 WAL 写入即可提交。 |
多节点/跨机房高可用。减少单个慢节点对主库写入延迟的影响,提供更平滑的容灾能力。 |
流复制参数解析:
sql
-- 1. 控制主节点可以同时处理多少个流复制连接
max_wal_senders = (物理备库数量 + 逻辑备库数量 + 2) * 1.5
-- 2. 控制可以创建的物理和逻辑复制槽数量:
max_replication_slots: 15 # 默认10,最小值4
-- 3. 控制在主节点上保留的WAL文件量,防止备库落后时无法同步
wal_keep_size: 1024MB # 默认128MB,最小值16MB
网络延迟 写入负载 推荐值 说明
<10ms 低 256MB 局域网环境,低负载
10-50ms 中 512MB 跨机房,中等负载
>50ms 高 1024MB+ 跨地域,高负载
-- 4. 最大槽WAL保留大小 (max_slot_wal_keep_size), PostgreSQL 13+ 引入的参数,控制单个复制槽保留的WAL量:
max_slot_wal_keep_size: -1 # -1表示无限制,或设置为具体MB值,防止单个落后备库占用过多磁盘空间
-- 5、 复制超时相关参数:
wal_sender_timeout: 60s # 发送超时
wal_receiver_timeout: 60s # 接收超时
replication_timeout: 60s # 复制超时
4.5.1 节点一配置
yaml
vim /pgsql/patroni/conf/patroni_postgresql.yml
scope: PGCluster
namespace: /pgsql/
name: pgsql1
restapi:
listen: 192.168.182.146:8008
connect_address: 192.168.182.146:8008
etcd:
hosts: 192.168.182.146:2379,192.168.182.147:2379,192.168.182.148:2379
bootstrap:
dcs:
ttl: 30 # leader 锁TTL
loop_wait: 10 #HA循环间隔
retry_timeout: 10 #重试超时时间
maximum_lag_on_failover: 1048576 #最大允许的WAL延迟(字节)
master_start_timeout: 300
synchronous_mode: true
synchronous_mode_strict: false
synchronous_standby_names: "pgsql2"
initialize: false
postgresql:
pg_hba:
- local all all trust
- host all all 127.0.0.1/32 trust
- host all all ::1/128 trust
- local replication all trust
- host all all 0.0.0.0/0 md5
- host replication replicator 192.168.182.255/24 md5
use_slots: true
use_pg_rewind: true
parameters:
listen_addresses: "*"
wal_level: hot_standby
hot_standby: on
max_connections: 2000
max_wal_senders: 50
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: on
track_commit_timestamp: off
archive_timeout: 1800s
archive_command: 'cp %p /data/pgwal/archive_wals/%f'
recovery_conf:
restore_command: 'cp /data/pgwal/archive_wals/%f %p'
postgresql:
callbacks:
on_start: /pgsql/vip_manager.sh
on_stop: /pgsql/vip_manager.sh
on_role_change: /pgsql/vip_manager.sh
listen: 0.0.0.0:5432
connect_address: 192.168.182.146:5432
data_dir: /data/pgdata/pg13
bin_dir: /pgsql/pghome/bin
authentication:
replication:
username: replicator
password: replicator@2025
superuser:
username: postgres
password: Admin@123
#Patroni允许通过标签系统精细控制节点的同步行为:
tags:
nofailover: false # 是否禁止故障转移
noloadbalance: false
clonefrom: false
nosync: false # 是否排除在同步候选外
# sync_priority: 1 同步优先级(0-100)
callbacks:回调函数,在数据库发生了启动,即重启和主库切换这些动作时,会调用配置的脚本进行其他动作,这里配置的是vip生成脚本,当主库发生启动,重启和切换时,都会调用这个脚本,保证主库上一直有vip用于连接。
4.5.2 节点二配置
yaml
vim /pgsql/patroni/conf/patroni_postgresql.yml
scope: PGCluster
namespace: /pgsql/
name: pgsql2
restapi:
listen: 192.168.182.147:8008
connect_address: 192.168.182.147:8008
etcd:
hosts: 192.168.182.146:2379,192.168.182.147:2379,192.168.182.148:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
master_start_timeout: 300
synchronous_mode: true
synchronous_mode_strict: false
synchronous_standby_names: "pgsql2"
initialize: false
postgresql:
pg_hba:
- local all all trust
- host all all 127.0.0.1/32 trust
- host all all ::1/128 trust
- local replication all trust
- host all all 0.0.0.0/0 md5
- host replication replicator 192.168.182.255/24 md5
use_slots: true
use_pg_rewind: true
parameters:
listen_addresses: "*"
wal_level: hot_standby
hot_standby: on
max_connections: 2000
max_wal_senders: 50
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: on
track_commit_timestamp: off
archive_timeout: 1800s
archive_command: 'cp %p /data/pgwal/archive_wals/%f'
recovery_conf:
restore_command: 'cp /data/pgwal/archive_wals/%f %p'
postgresql:
callbacks:
on_start: /pgsql/vip_manager.sh
on_stop: /pgsql/vip_manager.sh
on_role_change: /pgsql/vip_manager.sh
listen: 0.0.0.0:5432
connect_address: 192.168.182.147:5432
data_dir: /data/pgdata/pg13
bin_dir: /pgsql/pghome/bin
authentication:
replication:
username: replicator
password: replicator@2025
superuser:
username: postgres
password: Admin@123
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
4.5.3 节点三配置
yaml
vim /pgsql/patroni/conf/patroni_postgresql.yml
scope: PGCluster
namespace: /pgsql/
name: pgsql3
restapi:
listen: 192.168.182.148:8008
connect_address: 192.168.182.148:8008
etcd:
hosts: 192.168.182.146:2379,192.168.182.147:2379,192.168.182.148:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
master_start_timeout: 300
synchronous_mode: true
synchronous_mode_strict: false
synchronous_standby_names: "pgsql2"
initialize: false
postgresql:
pg_hba:
- local all all trust
- host all all 127.0.0.1/32 trust
- host all all ::1/128 trust
- local replication all trust
- host all all 0.0.0.0/0 md5
- host replication replicator 192.168.182.255/24 md5
use_slots: true
use_pg_rewind: true
parameters:
listen_addresses: "*"
wal_level: hot_standby
hot_standby: on
max_connections: 2000
max_wal_senders: 50
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: on
track_commit_timestamp: off
archive_timeout: 1800s
archive_command: 'cp %p /data/pgwal/archive_wals/%f'
recovery_conf:
restore_command: 'cp /data/pgwal/archive_wals/%f %p'
postgresql:
callbacks:
on_start: /pgsql/vip_manager.sh
on_stop: /pgsql/vip_manager.sh
on_role_change: /pgsql/vip_manager.sh
listen: 0.0.0.0:5432
connect_address: 192.168.182.148:5432
data_dir: /data/pgdata/pg13
bin_dir: /pgsql/pghome/bin
authentication:
replication:
username: replicator
password: replicator@2025
superuser:
username: postgres
password: Admin@123
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
4.6 创建 call_back 脚本
sql
#!/bin/bash
VIP=192.168.182.194
VIPBRD=192.168.182.255
VIPNETMASK=255.255.255.0
VIPNETMASKBIT=24
VIPDEV=ens33
VIPLABEL=1
LOGFILE="/pgsql/callback_$(date +%Y%m%d).log"
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/sbin:/usr/sbin
log()
{
printf "[%s] [%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOGFILE"
}
function usage() {
echo "Usage: $0 <on_start|on_stop|on_role_change> <role> <scope>"
exit 1
}
function addvip(){
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: Adding VIP $VIP to $VIPDEV"
sudo /sbin/ip addr add "$VIP/$VIPNETMASKBIT" brd "$VIPBRD" dev "$VIPDEV" label "$VIPDEV:$VIPLABEL"
log "added vip ${VIP} at dev ${VIPDEV}"
sudo /usr/sbin/arping -q -A -c 1 -I "$VIPDEV" "$VIP"
log "called arping to gateway 192.168.182.255"
}
function delvip(){
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: Deleting VIP $VIP from $VIPDEV"
sudo /sbin/ip addr del "$VIP/$VIPNETMASKBIT" dev "$VIPDEV" label "$VIPDEV:$VIPLABEL"
log "deleted vip ${VIP} at dev ${VIPDEV}"
sudo /usr/sbin/arping -q -A -c 1 -I "$VIPDEV" "$VIP" || echo "Failed to send ARP"
}
echo "$(date '+%Y-%m-%d %H:%M:%S') WARNING: patroni callback"
case "$1" in
on_stop)
delvip
;;
on_start)
;;
on_role_change)
if [[ "$2" == 'slave' ]] || [[ "$2" == 'replica' ]] || [[ "$2" == 'logical' ]]; then
delvip
else
addvip
fi
;;
*)
usage
;;
esac
记得预留 192.168.182.194 作为 VIP。
4.7 配置 Patroni 服务
shell
vim /usr/lib/systemd/system/patroni.service
[Unit]
Description=patroni - a high-availability PostgreSQL
Documentation=https://patroni.readthedocs.io/en/latest/index.html
After=syslog.target network.target etcd.target
Wants=network-online.target
[Service]
Type=simple
User=postgres
Group=postgres
PermissionsStartOnly=true
ExecStart=/usr/local/bin/patroni /pgsql/patroni/conf/patroni_postgresql.yml
ExecReload=/bin/kill -HUP $MAINPID
LimitNOFILE=65536
KillMode=process
KillSignal=SIGINT
Restart=on-abnormal
RestartSec=30s
TimeoutSec=0
[Install]
WantedBy=multi-user.target
4.8 启动Patroni服务
shell
sudo systemctl start patroni.service
sudo systemctl enable patroni.service
sudo systemctl status patroni.service
5. Patroni常用操作
5.1 查看集群状态
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml list

Sync Standby(同步备库):采用同步复制机制。主库在提交事务时,会等待至少一个同步备库确认已经接收到并写入 WAL(Write - Ahead Logging,预写式日志)数据后,才会将事务提交的结果返回给客户端。除了具备基本的读功能和数据备份功能外,在主库发生故障时,由于其与主库的数据一致性更好,通常会被自动提升为主库,以保证数据库服务的高可用性。Replica(异步副本):通常是异步复制模式。主库(Leader)在执行完客户端提交的事务后会立即将结果返回给客户端,并不关心从库(Replica)是否已经接收并处理,这种方式下主库的性能较高,因为不需要等待从库的响应。
对于 Sync Standby,主库"等待备库响应"的具体程度,可以通过 PostgreSQL 的 synchronous_commit 参数进行微调:
on(默认值) :主库等待备库将 WAL 日志写入备库磁盘(Flush) 后再返回提交成功(防备库宕机丢数据)。remote_write:主库仅等待备库将 WAL 日志写入备库操作系统缓存(Write) 即返回,延迟更低(但备库 OS 突然断电可能丢数据)。remote_apply:主库等待备库不仅刷盘、而且将 WAL 实际回放(Apply)到数据库 后才返回。此模式下,客户端立刻去备库查询即可读到最新数据(消除读写分离的"读延迟")。
5.2 手动强制切换
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml switchover PGCluster --leader pgsql3 --candidate pgsql1 --force

5.3 验证自动切换
重启 leader 节点服务器

pgsql3 切换为主节点,pgsql1 重启好后,以备机的身份加入集群中

5.4 在线调整参数
shell
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml edit-config
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml edit-config -p "synchronous_mode_strict=off"
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml edit-config -p "synchronous_mode=on"
在使用 Patroni 托管 PostgreSQL 后,就不要直接手动修改 postgresql.conf 文件。
5.5 重启整个集群
shell
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml restart PGCluster
(所有节点依次重启:

5.6 仅重启某个节点
shell
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml restart <cluster_name> <member_name>
5.7 仅让实例重载配置
shell
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml reload <cluster_name> [--force]

5.8 状态监控
sql
SELECT
client_addr,
application_name,
state,
sync_state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) as replay_lag_bytes,
pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn) as flush_lag_bytes
FROM pg_stat_replication;
5.9 清理 ETCD 元数据(慎用)
shell
etcdctl rm --recursive /pgsql/ #YAML文件中 namespace:参数的值
etcdctl del --prefix /pgsql/
patronictl -c /pgsql/patroni/conf/patroni_postgresql.yml remove PGCluster
6. 总结
本文详细介绍了 PG + Patroni + ETCD 高可用容灾集群的搭建过程,并列举了 Patroni 的常用运维场景。无论是开源生态中的 Patroni,还是国产商业数据库中的 HAS 与 CM 体系,其底层逻辑都离不开"状态感知、共识仲裁、自动切换"这十二个字。高可用架构从来没有绝对的终点,唯有充分的演练与针对具体业务场景的不断调优。
** 这里是《实战派K8S&DB》,更多干货敬请关注公众号。如果本文对你有所帮助,欢迎点赞、推荐和转发,也欢迎关注后续文章,一起考证、一起学习数据库技术。**