从原生 PG 到 Vastbase、GaussDB:聊透“Patroni + ETCD”高可用架构演进与实战

从原生 PG 到 Vastbase、GaussDB:聊透"Patroni + ETCD"高可用架构演进与实战

  昨天我们介绍了 PostgreSQL 的一主两从搭建过程,并详细说明了 synchronous_standby_names 参数在 ANYFIRST等不同配置下的同步差异,尽管可以保障数据冗余,但无法提供高可用自动切换能力。因此,本期我们将手把手搭建 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(基于 DCF Paxos 构建的 KV 状态机) 承接集群拓扑与配置存储; DN 节点选主则由 DCF 基于 Paxos 协议自治完成(XLOG 与 DCF 日志合一),完全脱离了对外部 ETCD 的依赖。

  简单说就是: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 常用命令

  1. 查看集群成员
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
  1. 查看目录
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》,更多干货敬请关注公众号。如果本文对你有所帮助,欢迎点赞、推荐和转发,也欢迎关注后续文章,一起考证、一起学习数据库技术。**

相关推荐
一个天蝎座 白勺 程序猿1 小时前
SQL Server数据库迁移实测:金仓KES V9R4C019让存量T-SQL“少量修改”
数据库·sql·kingbasees
嘻哈baby1 小时前
FastAPI + SQLite 从 0 写一个真正能用的待办 API
数据库·sqlite·fastapi
judezh1 小时前
「可重放」不是形容词:我把自家 Agent 运行时的 run 账本翻了个底朝天
数据库·人工智能
落木萧萧8252 小时前
MyBatis 启动的时候都在干什么:从 MappedStatement 说起
java·数据库·后端
g10565591392 小时前
华为 OceanStor 基础使用入门指南
服务器·数据库·性能优化
潇凝子潇2 小时前
MySQL buffer pool 计算公式
数据库·mysql
广州灵眸科技有限公司2 小时前
瑞芯微(EASY EAI)RV1126B display
开发语言·数据库·人工智能·科技·嵌入式硬件
凌晨1682 小时前
MySQL:DML、DDL与TCL精讲
数据库·mysql·oracle
风哥2号2 小时前
数据库教程FGMT04‑生产环境Linux+Oracle19c RAC集群安装配置与项目实战
linux·数据库