找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1615

积分

1

好友

227

主题
发表于 前天 20:12 | 查看: 4| 回复: 0

背景

单机PostgreSQL数据库在面临服务器硬件故障、操作系统崩溃或网络中断时,容易导致服务中断,无法保证业务连续性。这种架构缺乏高可用机制,故障恢复依赖人工干预,不仅操作复杂,而且恢复时间目标(RTO)较长,难以满足现代业务对高可靠性、可扩展性及容灾能力的需求。

为确保数据库服务的高可用性,避免因宕机影响业务,构建健壮的PostgreSQL高可用(HA)架构至关重要。借助Patroni、HAProxy、Keepalived与etcd等组件的协同工作,可以有效地实现这一目标。

组件介绍

Patroni

Patroni是一个基于Python构建的PostgreSQL高可用性解决方案。它支持多种分布式配置存储后端,如ZooKeeper、etcd、Consul或Kubernetes,兼容PostgreSQL 9.3及以上版本,负责自动化故障转移、集群状态管理与PostgreSQL实例的生命周期管理。

HAProxy

HAProxy是一款高性能的开源负载均衡器与反向代理,支持TCP和HTTP应用。它能高效分配工作负载,从而提升应用性能,显著缩短响应时间并提高吞吐量。在本架构中,它负责将客户端读写请求智能路由到正确的PostgreSQL节点。

Keepalived

Keepalived是一个提供负载均衡和高可用性功能的框架。它通过实现一组健康检查器,能够根据后端服务器的健康状况动态地维护和管理服务器池。在本方案中,它主要用于创建和管理一个虚拟IP(VIP),实现客户端的无感知故障切换。

ETCD

ETCD是一个高度一致的分布式键值存储,为分布式系统或机器集群提供了可靠的数据存储访问方式。它能够优雅地处理网络分区期间的领导者选举,并容忍机器故障。在本架构中,etcd集群用于存储PostgreSQL高可用集群的配置与状态数据,供Patroni、HAProxy和Keepalived协调使用。

watchdog

watchdog进程负责监控PostgreSQL节点及其相关进程的健康状况。它确保节点正常运行并能处理请求。一旦检测到问题,watchdog可以采取措施恢复节点或触发到备用节点的故障转移,是防止“脑裂”情况的关键组件。

环境信息

hostname IP 地址 CPU(Core) mem 配置组件
mdw 10.0.12.9 4 8GB etcd, HAProxy, keepalived, Patroni and PostgreSQL, pgBouncer
standby 10.0.12.4 4 8GB etcd, HAProxy, keepalived, Patroni and PostgreSQL, pgBouncer
standby1 10.0.16.11 4 8GB etcd, HAProxy, keepalived, Patroni and PostgreSQL, pgBouncer
ha-vip 10.0.12.10 4 8GB HA-VIP 高可用虚拟IP

防火墙设置

防火墙直接关闭

若环境允许,关闭防火墙是最简单的方式。

-- 关闭防火墙
sudo systemctl stop firewalld
-- 查看防火墙的状态
sudo systemctl status firewalld

开放指定的端口

若需保持防火墙开启,则需按需开放以下组件端口。

Patroni
  • 8008:用于Patroni的HTTP API
    sudo firewall-cmd --zone=public --add-port=8008/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=8008/tcp
HAProxy
  • 5000:用于HTTP后端连接。
  • 5001:用于HTTPS后端连接。
    sudo firewall-cmd --zone=public --add-port=5000/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5001/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=5000/tcp
    sudo firewall-cmd --query-port=5001/tcp
etcd
  • 2379:用于etcd客户端通信。
  • 2380:用于etcd节点间通信。
    sudo firewall-cmd --zone=public --add-port=2379/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=2380/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=2379/tcp
    sudo firewall-cmd --query-port=2380/tcp
Keepalived
  • 112:用于VRRP协议通信。
  • 5405:用于多播流量。
    sudo firewall-cmd --zone=public --add-port=112/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5405/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=112/tcp
    sudo firewall-cmd --query-port=5405/tcp
Pgbouncer
  • 6432:用于Pgbouncer客户端连接。
    sudo firewall-cmd --zone=public --add-port=6432/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=6432/tcp
PostgreSQL
  • 5432:用于PostgreSQL客户端连接。
    sudo firewall-cmd --zone=public --add-port=5432/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --query-port=5432/tcp
Web server
  • 5000, 5001:用于Web服务器HTTP/HTTPS连接。
  • 7000:用于从Web服务器到HAProxy的反向代理。
    sudo firewall-cmd --zone=public --add-port=5000/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5001/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=7000/tcp --permanent
    sudo firewall-cmd --reload

安装 PostgreSQL 17

在所有节点上安装PostgreSQL 17(仅安装,不初始化),Patroni将在启动时自动初始化数据库实例。

-- 安装编译工具和依赖
sudo yum groupinstall "Development Tools" -y
sudo yum install readline-devel zlib-devel libicu-devel openssl-devel pam-devel libxml2-devel libxslt-devel systemd-devel -y

-- 创建用户和数据目录
sudo groupadd postgres
sudo useradd -g postgres postgres
sudo passwd postgres

sudo mkdir -p /opt/pgsql
sudo chown postgres:postgres /opt/pgsql
sudo mkdir -p /opt/pgdata17.4
sudo chown postgres:postgres /opt/pgdata17.4

-- 下载并编译安装PostgreSQL
cd /root
wget https://ftp.postgresql.org/pub/source/v17.4/postgresql-17.4.tar.gz
tar -zxvf postgresql-17.4.tar.gz

cd postgresql-17.4
./configure --prefix=/opt/pgsql --with-openssl --with-libxml --with-icu --with-systemd
make -j$(nproc)
sudo make install

部署 ETCD 集群

在所有三个节点上部署etcd,组成高可用的etcd集群,为Patroni提供可靠的配置存储服务。深入理解分布式键值存储与中间件的原理,对于维护此类高可用架构至关重要。

源码安装 ETCD 节点

安装 GO 程序
yum install -y go
编译 ETCD
git clone https://github.com/etcd-io/etcd.git
cd etcd
git checkout v3.5.12
./build.sh
sudo cp bin/etcd* /usr/local/bin/
配置 ETCD 服务

配置主机名与IP映射:

10.0.12.4 standby
10.0.12.9 mdw
10.0.16.11 standby1

mdw 节点配置 /etc/etcd/etcd.conf.yml:

name: mdw
data-dir: /var/lib/etcd
listen-peer-urls: http://10.0.12.9:2380
listen-client-urls: http://10.0.12.9:2379,http://127.0.0.1:2379
advertise-client-urls: http://10.0.12.9:2379
initial-advertise-peer-urls: http://10.0.12.9:2380
initial-cluster: standby=http://10.0.12.4:2380,mdw=http://10.0.12.9:2380,standby1=http://10.0.16.11:2380
initial-cluster-token: etcd-cluster-01
initial-cluster-state: new

standby 节点配置(仅 name 和涉及自身IP的字段不同):

name: standby
data-dir: /var/lib/etcd
listen-peer-urls: http://10.0.12.4:2380
listen-client-urls: http://10.0.12.4:2379,http://127.0.0.1:2379
advertise-client-urls: http://10.0.12.4:2379
initial-advertise-peer-urls: http://10.0.12.4:2380
initial-cluster: standby=http://10.0.12.4:2380,mdw=http://10.0.12.9:2380,standby1=http://10.0.16.11:2380
initial-cluster-token: etcd-cluster-01
initial-cluster-state: new

standby1 节点配置:

name: standby1
data-dir: /var/lib/etcd
listen-peer-urls: http://10.0.16.11:2380
listen-client-urls: http://10.0.16.11:2379,http://127.0.0.1:2379
advertise-client-urls: http://10.0.16.11:2379
initial-advertise-peer-urls: http://10.0.16.11:2380
initial-cluster: standby=http://10.0.12.4:2380,mdw=http://10.0.12.9:2380,standby1=http://10.0.16.11:2380
initial-cluster-token: etcd-cluster-01
initial-cluster-state: new

每个节点配置systemd服务文件 /etc/systemd/system/etcd.service

[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd
After=network.target

[Service]
Type=notify
User=etcd
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.conf.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

启动并验证etcd集群:

sudo systemctl daemon-reload
sudo systemctl start etcd
sudo systemctl enable etcd
sudo systemctl status etcd

查看集群状态与健康:

etcdctl --endpoints=http://10.0.12.9:2379,http://10.0.12.4:2379,http://10.0.16.11:2379 endpoint status -w table
etcdctl --endpoints=http://10.0.12.9:2379 member list -w table
etcdctl --endpoints=http://10.0.12.9:2379 endpoint health --cluster

部署 keepalived

在每台服务器上部署Keepalived以创建VIP,实现客户端无感知故障切换。

yum install -y keepalived
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sudo sysctl --system
sudo sysctl -p

配置 keepalived.conf 文件

使用 ifconfig 获取网络接口名(如eth0),并在每台机器上配置。

配置 mdw (MASTER)
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.back

编辑 /etc/keepalived/keepalived.conf

vrrp_script check_haproxy {
  script "pkill -0 haproxy"
  interval 2
  weight 2
}
vrrp_instance VI_1 {
  state MASTER
  interface eth0
  virtual_router_id 51
  priority 101
  advert_int 1
  virtual_ipaddress {
    192.168.231.140
  }
  track_script {
    check_haproxy
  }
}
配置 standby 和 standby1 (BACKUP)

配置内容类似,主要区别在于 state BACKUPpriority 100

vrrp_script check_haproxy {
   script "pkill -0 haproxy"
   interval 2
   weight 2
}
vrrp_instance VI_1 {
  state BACKUP
  interface eth0
  virtual_router_id 51
  priority 100
  advert_int 1
  virtual_ipaddress {
    192.168.231.140
  }
  track_script {
    check_haproxy
  }
}

开启 keepalived 服务

每台机器上执行:

systemctl start keepalived
systemctl enable keepalived
systemctl status keepalived

使用 ip addr 命令检查各节点是否成功绑定了虚拟IP 192.168.231.140

配置 HAProxy

安装 HAProxy

yum install -y haproxy

配置HAProxy

在mdw节点上配置 /etc/haproxy/haproxy.cfg,此配置是运维与DevOps实践中负载均衡的典型应用。

cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.back

将以下配置写入文件:

# /etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    maxconn 1000

defaults
    mode tcp
    log global
    option tcplog
    retries 3
    timeout queue 1m
    timeout connect 4s
    timeout client 60m
    timeout server 60m
    timeout check 5s
    maxconn 900

# 监控页面(HTTP)
listen stats
    mode http
    bind *:7000
    stats enable
    stats uri /
    stats refresh 10s
    stats admin if TRUE

# 写流量:只路由到主库(Patroni /master 返回 200)
listen primary
    bind 192.168.231.140:5000
    mode tcp
    balance first
    option httpchk OPTIONS /master
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server mdw      10.0.12.9:5432   maxconn 100 check port 8008
    server standby  10.0.12.4:5432   maxconn 100 check port 8008
    server standby1 10.0.16.11:5432  maxconn 100 check port 8008

# 读流量:可路由到任意副本(/replica 或 /read-only 返回 200)
listen standby
    bind 192.168.231.140:5001
    mode tcp
    balance roundrobin
    option httpchk OPTIONS /replica
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server mdw      10.0.12.9:5432   maxconn 100 check port 8008
    server standby  10.0.12.4:5432   maxconn 100 check port 8008
    server standby1 10.0.16.11:5432  maxconn 100 check port 8008

校验并分发配置

sudo haproxy -c -f /etc/haproxy/haproxy.cfg
scp /etc/haproxy/haproxy.cfg standby:/etc/haproxy/haproxy.cfg
scp /etc/haproxy/haproxy.cfg standby1:/etc/haproxy/haproxy.cfg

创建目录并赋权(每台服务器)

sudo mkdir -p /var/lib/haproxy
sudo chown root:root /var/lib/haproxy
sudo chmod 755 /var/lib/haproxy
sudo mkdir -p /run/haproxy
sudo chown haproxy:haproxy /run/haproxy
sudo chmod 755 /run/haproxy

启动服务(每台服务器)

sudo systemctl daemon-reload
systemctl start haproxy
systemctl enable haproxy
systemctl status haproxy

启用 watchdog

Watchdog用于防止Patroni进程假死(脑裂),当Patroni无法正常发送心跳时,系统将在超时后自动重启节点。

watchdog 安装部署(每台节点)

sudo yum install -y watchdog
sudo modprobe softdog
echo "softdog" | sudo tee /etc/modules-load.d/softdog.conf

lsmod | grep softdog

sudo cat /etc/watchdog.conf | grep -v "^#" | grep -v "^$"
# 确保包含以下行(或类似):
# watchdog-device    = /dev/watchdog
# realtime        = yes
# priority        = 1

echo 'KERNEL=="watchdog", MODE="0600", OWNER="postgres"' | sudo tee /etc/udev/rules.d/99-watchdog.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=watchdog
sudo chown -R postgres:postgres /dev/watchdog

使用 Patroni 安装 PostgreSQL 17

在每个节点部署Patroni以管理PostgreSQL实例。

安装 Patroni

sudo yum install -y python3 python3-pip
sudo pip3 install patroni
patroni --version

配置 Patroni

每个节点的配置文件 (/etc/patroni.yml) 需单独配置,主要区别在于 namerestapilisten/connect_address 以及 postgresqllisten/connect_address

mdw 节点配置示例
scope: watchdogmycluster          # 集群名,所有节点一致
namespace: /db           # etcd 命名空间(可选)
name: mdw                # 本节点名称(每台机器不同)
restapi:
  listen: 10.0.12.9:8008
  connect_address: 10.0.12.9:8008
etcd3:
    hosts:                # etcd 集群地址
    - 10.0.12.9:2379
    - 10.0.12.4:2379
    - 10.0.16.11:2379
bootstrap:
  allow_bootstrap: true
  dcs:
    ttl: 30               # leader 租约时间(秒)
    loop_wait: 10         # 主节点状态上报间隔
    retry_timeout: 10     # 故障重试超时
    maximum_lag_on_failover: 1048576  # 最大允许 lag(1MB)
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_level: replica
        hot_standby: on
        max_wal_senders: 10
        wal_keep_size: 128MB
        max_replication_slots: 5
        password_encryption: md5
  pg_hba:
    - host replication replicator 0.0.0.0/24 md5
    - host replication replicator 10.0.12.4/32 md5
    - host replication replicator 10.0.12.9/32 md5
    - host replication replicator 10.0.16.11/32 md5
    - host    postgres        postgres        10.0.12.4/32       trust
    - host    postgres        postgres        10.0.12.9/32       trust
    - host    postgres        postgres        10.0.16.11/32      trust
  initdb:
    - encoding: UTF8
    - data-checksums
    - "auth-host=md5"
    - "auth-local=trust"
postgresql:
  listen: 10.0.12.9:5432
  connect_address: 10.0.12.9:5432
  data_dir: /opt/pgdata17.4
  bin_dir: /opt/17.4/bin/
  pgpass: /tmp/pgpass
  authentication:
    replication:
      username: replicator
      password: rep_pass
    superuser:
      username: postgres
      password: postgres_pass
  parameters:
    password_encryption: md5
    unix_socket_directories: '/tmp'
watchdog:
  mode: required
  device: /dev/watchdog
  safety_margin: 5
tags:
    nofailover: false
    noloadbalance: false
    clonefrom: false
    nosync: false

standbystandby1 节点的配置与之类似,需相应修改 name 和涉及本机IP的字段。

配置 patroni.service 服务(每台机器)

创建或修改 /etc/systemd/system/patroni.service

[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target

[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni.yml
KillMode=process
TimeoutSec=30
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
创建PG数据目录并赋权(每台机器)
mkdir -p /opt/pgdata17.4
chown -R postgres:postgres /opt/pgdata17.4
启动 patroni 服务(每台机器)
sudo systemctl daemon-reload
sudo systemctl start patroni
sudo systemctl status patroni

若部署异常,可使用 etcdctl --endpoints=* del "/db/mycluster/" --prefix 删除key后重新初始化。

查看集群状态
patronictl -c /etc/patroni.yml list watchdogmycluster

输出列说明:

  • Member: 节点名称(patroni.yml中的name
  • Host: PostgreSQL监听IP
  • Role: Leader(主库)或 Replica(备库)
  • State: running(运行中)、streaming(流复制中)等
  • TL: WAL时间线编号
  • Receive LSN/Lag: 备库接收WAL的位置及延迟
  • Replay LSN/Lag: 备库重放WAL的位置及延迟(关键故障转移指标)
通过HAProxy连接测试

在各节点上测试通过VIP连接数据库:

psql -h 192.168.231.140 -p 5000

模拟故障与测试

手动切换Leader(Switchover)

使用 patronictl switchover 命令可将主库角色从当前节点安全地切换到指定的备库,观察TL(时间线)递增。

模拟主库故障(Failover)

直接停止当前Leader节点的patroni服务 (systemctl stop patroni),观察集群如何自动选举新的Leader。原Leader节点恢复服务后,会自动以Replica角色重新加入集群。

核心参数说明

控制Patroni行为的关键参数(位于bootstrap.dcs):

  • ttl (30): Leader锁的存活时间。主库须在此时间内续租,否则触发故障转移。
  • loop_wait (10): Patroni主循环检查间隔。
  • retry_timeout (10): 单次操作(如连接DB、获取锁)超时时间。
  • maximum_lag_on_failover (1MB): 故障转移时允许的备库最大复制延迟。

故障恢复时间估算ttl + loop_wait + promote_time(通常40-60秒)。

业务连续性测试

在主库创建测试表后,使用脚本模拟业务持续写入(通过HAProxy的VIP)。此时停止主库patroni服务,观察脚本日志。在短暂的自动故障转移期间,可能会有个别连接错误,但转移完成后写入应立即恢复,验证了高可用架构的有效性。这种架构是构建稳健云原生与基础设施服务的数据层基石。




上一篇:从零开始配置高效Emacs编辑器:主题、插件与实用技巧
下一篇:eza命令行工具深度体验:Git集成、彩色输出,现代ls替代方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 18:57 , Processed in 0.189868 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表