ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PostgreSQL高可用架构实战:流复制+pgpool-II部署与Failover排坑指南

PostgreSQL高可用架构实战:流复制+pgpool-II部署与Failover排坑指南

简介:Postgres主从流复制+pgpool高可用方案,是一份面向数据库运维、DBA及架构师的实操型技术文档,解决生产环境中PostgreSQL单点故障、读写性能瓶颈及连接管理问题,适用已掌握基础SQL与实例配置的中高级读者。方案基于流复制协议,通过WAL日志实现主备节点实时同步,可配置同步或异步两种复制模式,并结合pgpool-II提供连接池、负载均衡、读写分离与主故障自动切换能力;文档还兼顾备份恢复工具pg_rman,体系完整。内容按章节展开:先介绍方案设计与两种复制模式对比,再给出实践环境和示例拓扑,随后说明客户环境准备(软件安装、postgres用户创建、目录权限),并重点列出资源调整项,如关闭防火墙、SELinux、hosts配置、时钟同步、sysctl参数与limit分配。每个环节均给出配置要点与操作顺序,适合按步骤搭建、验证故障切换,也便于在部署中快速定位参数问题。资源为单个docx文件,压缩包大小约773KB,已有469人学习,适合作为高可用环境部署前的参考手册与排错清单。

1. 一套扛得住主库宕机的PG高可用方案:流复制加pgpool,装过才知道坑在哪

数据库高可用这个话题,PostgreSQL用户绕不开两条线:一条是流复制做主备数据同步,另一条是pgpool-II做连接池、读写分离和故障切换。单装一个PostgreSQL并不难,难的是把它们串成一个整体,并且让主库挂掉之后备库能自动顶上,客户端连的地址还不发生变化。这套方案在客户环境里很常见,RHEL或CentOS下部署PostgreSQL 12.2与pgpool-II 4.1.1,配合pg_rman做离线备份,覆盖了在线同步、读写分离、离线恢复三个环节。装过一轮的人会有同感:正常安装不难,难的是版本差异、认证配置和切换细节。这篇笔记按实际部署顺序写,把装什么版本、为什么这么装、装坏了怎么排查都交代清楚。

2. 资源调整与基础配置:先把用户、防火墙、hosts、sysctl这些底座打稳

中间件再怎么折腾,地基不稳照样翻车。PG与pgpool的部署对系统环境有一定要求,这一步做不扎实,后边流复制起不来、watchdog误判是常事。所有节点先把系统层面统一好,再碰数据库安装。

2.1 创建postgres用户与统一规划安装目录

主备两台机器都要求使用postgres系统用户运行数据库。不要用root跑PG,一是权限模型不干净,二是日志、数据文件的属主一乱,pg_rman恢复时会先报一堆文件权限错误。我在每台节点上先建用户和目录,后续安装、初始化、起服务全部以postgres身份执行。

useradd -m -s /bin/bash postgres echo "postgres" | passwd --stdin postgres mkdir -p /data/postgresql /data/pgpool /data/pgbackup chown -R postgres:postgres /data

需要说明的是,passwd --stdin适合安装脚本里用,交互式环境建议手动执行passwd postgres。目录规划上我喜欢把数据库数据目录放在/data/postgresql/data,pgpool运行目录放/data/pgpool,备份目录放/data/pgbackup,三块独立,后面备份脚本和failover脚本都基于这套目录书写。

2.2 网络与系统参数:防火墙、selinux、hosts、时钟同步、sysctl、limit

这部分必须在安装数据库之前处理,否则后面会出现各种环境性报错,而且报错信息往往指向不明。按顺序走比较省事。

防火墙方面,生产环境一般不建议直接关闭,而是放行5432(PostgreSQL)、9999(pgpool)、9898(pcp)、9694(watchdog心跳)等端口。如果测试环境想省事,systemctl stop firewalld加上systemctl disable firewalld也可以,但我在客户环境里一律采用放行端口的方式。

selinux建议设为permissive,除非有专门的selinux策略文件。PG和pgpool官方文档在selinux enforcing下会出现各种意想不到的拒绝访问,排查成本高,permissive是运维最常见的折中方案。

cp /etc/hosts /etc/hosts.bak cat >> /etc/hosts <<'EOF' 192.168.10.11 pg-master 192.168.10.12 pg-standby 192.168.10.100 pg-vip EOF

hosts文件里主备两台的主机名必须互写,pgpool的watchdog和failover脚本都依赖主机名解析。虚拟IP建议也写进hosts,连接测试时直接用名字连,少一层排查。

时钟同步用chrony或ntp都行,关键是主备节点时间差不能太大。流复制本身对时间不敏感,但pgpool的watchdog心跳机制对超时敏感,如果节点间时差超过心跳超时阈值,活着的节点可能被误判为宕机,触发错误的failover,这个坑我踩过不止一次。

sysctl -w kernel.shmall=2097152 sysctl -w kernel.shmmax=8589934592 echo "postgres soft nofile 65536" >> /etc/security/limits.conf echo "postgres hard nofile 65536" >> /etc/security/limits.conf echo "postgres soft nproc 131072" >> /etc/security/limits.conf

sysctl参数里,kernel.shmmax建议至少是shared_buffers的两倍。shared_buffers一般设为物理内存的25%,16G内存的机器建议shmmax给8G以上。nofile和nproc的limit配置直接关系到PG在高并发连接场景下的稳定性,连接数一上来就报too many open files的基本都是这里没配好。

2.3 离线环境的准备

RHEL客户环境经常不能联网安装依赖包,这需要在部署前用“RHEL安装环境获取脚本”先配置好本地安装源并保存rpm缓存。实际操作中我会先准备一台能联网的同版本机器,把依赖包缓存下载完整,再拷贝到生产机上解压安装。这个环节省不了,等到make install时报缺库再去找包,既耽误时间又容易把依赖搞乱。

3. PostgreSQL 12.2流复制部署:从initdb到walsender跑通

流复制的核心是主库的walwriter周期性地把WAL日志刷新到磁盘,walsender进程把WAL page发送给备库的walreceiver,备库的startup进程不断回放日志,保持与主库的数据同步。PG 12.2与旧版本相比,最大的变化是备库标识从recovery.conf文件改成了standby.signal标志文件,配置方式完全不同,这也是老手最容易翻车的地方。

3.1 依赖包与编译安装

PG源码编译安装依赖gcc、readline-devel、zlib-devel等。在RHEL离线环境下,依赖包需要通过本地repo安装,否则解压后configure阶段直接报缺头文件。

yum install -y gcc readline-devel zlib-devel make tar -zxvf postgresql-12.2.tar.gz -C /usr/local/src cd /usr/local/src/postgresql-12.2 ./configure --prefix=/usr/local/pgsql make && make install

--prefix指定安装路径为/usr/local/pgsql,后续环境变量、pg_hba.conf路径都基于这个前缀。12.2版本在RHEL 7.5上编译没有问题,如果遇到缺perl或python相关的模块,按configure报错提示补装即可。生产环境我不建议用--with-python这类针对PG自身开发用的扩展选项,编译出的二进制越干净越不容易出问题。

3.2 环境变量与initdb初始化

编译安装完成后,所有涉及PG的操作都需要环境变量。这里的路径必须与configure时的prefix一致,否则命令找不到、数据目录识别不出来。

cat >> /home/postgres/.bash_profile <<'EOF' export PATH=/usr/local/pgsql/bin:$PATH export PGDATA=/data/postgresql/data export PGHOST=/tmp EOF

PGHOST=/tmp是PG默认的Unix socket目录,pgpool连接测试时经常用socket连,不设置的话可能连不上。初始化数据库时,locale建议用C或en_US.UTF-8,不要选zh_CN,除非业务明确需要中文排序规则,否则字符集不一致会把索引和排序搞出玄学问题。

su - postgres initdb -D /data/postgresql/data -U postgres --encoding=UTF8 --locale=C

initdb执行完毕会生成postgresql.conf、pg_hba.conf等文件。注意initdb默认生成的是样例配置,参数需要按实际情况调整,不要直接拿默认值跑生产。

3.3 主库参数调整与pg_hba.conf配置

主库的postgresql.conf是整个流复制的源头。wal_level必须设置为replica,否则备库连上来后主库不会启动walsender进程发送WAL日志。

listen_addresses = '*' port = 5432 wal_level = replica max_wal_senders = 10 wal_keep_segments = 64 synchronous_commit = off synchronous_standby_names = ''

max_wal_senders决定最多允许多少个备库连接,单备库环境配10保留余量。wal_keep_segments表示保留多少份WAL段文件,如果备库停机时间过长,主库的WAL段已经被循环覆盖,备库重连时会发现同步起点丢失,需要重新pg_basebackup。这个参数在磁盘空间允许的情况下建议给大一些。

pg_hba.conf是主库的访问控制文件,流复制用户与普通连接用户都需要在这里配置白名单。

host replication repluser 192.168.10.12/32 md5 host all all 192.168.10.0/24 md5

第一行是允许备库以repluser身份拉取WAL流,第二行是允许应用服务器连接。生产环境中不要把第二行写成0.0.0.0/0,按实际网段收紧。

3.4 创建流复制专用用户并启动主库

流复制用户只赋予复制权限,不授予超级用户权限。这是兼顾安全与合规的常见做法,也是我在客户环境里主推的方式。

CREATE ROLE repluser REPLICATION LOGIN PASSWORD 'Repl@123456';

启动主库后确认进程状态,walsender进程要等到备库连接后才出现。主库启动命令:

pg_ctl -D /data/postgresql/data -l /data/postgresql/logfile start

启动完毕后执行pg_isready检查端口是否监听。如果出现could not identify user之类的错误,多半是pg_hba.conf没reload,执行pg_ctl reload即可。

3.5 备库部署:pg_basebackup与standby.signal

备库搭建最标准的流程是从主库做一次全量基础备份,然后通过参数-R自动生成备库标识和连接信息。先清空备库数据目录,再执行备份。注意-R参数会生成standby.signal,并自动在postgresql.conf里追加primary_conninfo,这是12.x版本的新机制。

rm -rf /data/postgresql/data/* pg_basebackup -h 192.168.10.11 -U repluser -D /data/postgresql/data -P -R -X stream

-X stream表示WAL日志以流式方式同步传输,而不是等归档。执行完毕后检查备库数据目录中是否存在standby.signal文件,如果没有说明-R参数没有生效,需要手动创建touch /data/postgresql/data/standby.signal。

3.6 备库primary_conninfo与启动

pg_basebackup的-R参数虽然自动生成了primary_conninfo,但密码不会写入,需要手动补全,否则备库启动时报认证失败,反复重连主库,看日志全是FATAL: password authentication failed。

primary_conninfo = 'host=192.168.10.11 port=5432 user=repluser password=Repl@123456 application_name=standby1'

备库的postgresql.conf不要复制主库的完整配置,特别是max_connections等参数最好与主库一致。因为PG在主备切换后,备库的配置就是新主的配置,如果备库的max_connections比主库小,新主在业务量不变的情况下会直接报连接数不足。启动备库并检查状态:

pg_ctl -D /data/postgresql/data -l /data/postgresql/logfile start psql -c "select * from pg_stat_replication;"

在主库执行上述查询,如果state列为streaming,sync_state为async,说明流复制已经跑通。备库日志中应能看到streaming replication started字样。

3.7 同步与异步的参数取舍

文档中明确提到,配置同步复制需要synchronous_standby_names非空且synchronous_commit=on。同步模式保证主库事务提交前WAL已经写到备库,数据零丢失,但事务响应时间会增加。异步模式延迟通常在1秒以内,主库崩溃时可能丢失少量数据。

我一般建议客户在业务容忍范围内优先选异步,然后通过pgpool的健康检查与自动切换来保障整体主备可用性。只有当业务明确要求零丢失并且网络质量有保障时,才启用同步模式。这个取舍要让业务方参与决策,DBA单独拍板容易事后背锅。

4. pgpool-II 4.1.1安装配置:连接池、读写分离与failover的完整链路

pgpool-II是位于应用与PG之间的中间件,它把客户端的连接池化,select查询分发到各后端节点实现读写分离,同时用watchdog机制监控后端节点状态并在主库故障时触发failover脚本完成自动切换。4.1.1版本与3.6.x版本在核心功能上一致,但部分参数名称和默认行为有变化。

4.1 编译安装与依赖

pgpool编译同样需要gcc、libpq等依赖。如果系统中已经存在PG的libpq库,configure会自动识别;否则需要指定--with-pgsql路径。

tar -zxvf pgpool-II-4.1.1.tar.gz -C /usr/local/src cd /usr/local/src/pgpool-II-4.1.1 ./configure --prefix=/usr/local/pgpool make && make install

安装完成后的二进制文件在/usr/local/pgpool/bin,配置文件在/usr/local/pgpool/etc。

4.2 安装相关函数到PG数据库

pgpool提供的insert_lock和pgpool-regclass函数需要安装到PG数据库中,否则并发插入场景下可能产生锁冲突。文档中明确要求“安装相关函数”,这步很多人会漏掉,导致pgpool连接池模式下的两阶段提交或插入加锁行为异常。

psql -f /usr/local/src/pgpool-II-4.1.1/sql/pgpool-regclass/pgpool-regclass.sql postgres psql -f /usr/local/src/pgpool-II-4.1.1/sql/pgpool-recovery/pgpool-recovery.sql postgres

这两个SQL文件在源码树的sql目录下,编译安装后不会复制到prefix目录,需要从源码目录执行。函数安装到postgres数据库即可,pgpool运行时会自动调用。

4.3 环境变量与工作目录

pgpool运行需要PATH与PGPOOL_HOME环境变量。主备两台机器都要执行同样的配置,因为failover后备库可能变为新主,pgpool节点也可能发生角色切换。

cat >> /home/postgres/.bash_profile <<'EOF' export PATH=/usr/local/pgpool/bin:$PATH export PGPOOL_HOME=/usr/local/pgpool EOF mkdir -p /var/run/pgpool /var/log/pgpool /data/pgpool chown -R postgres:postgres /var/run/pgpool /var/log/pgpool /data/pgpool

运行目录和日志目录分开,排错的时候直接tail -f /var/log/pgpool/pgpool.log,不用满系统找日志。

4.4 pgpool.conf核心参数:4.x版本说明

pgpool.conf是pgpool的整个配置核心,主备节点各一份,watchdog配置略有差异。下面列的是双节点环境下最关键的一组参数。

listen_addresses = '*' port = 9999 socket_dir = '/var/run/pgpool' pcp_port = 9898 pcp_socket_dir = '/var/run/pgpool' backend_hostname0 = '192.168.10.11' backend_port0 = 5432 backend_weight0 = 1 backend_data_directory0 = '/data/postgresql/data' backend_hostname1 = '192.168.10.12' backend_port1 = 5432 backend_weight1 = 1 backend_data_directory1 = '/data/postgresql/data' enable_pool_hba = on pool_hba_file = '/usr/local/pgpool/etc/pool_hba.conf' load_balance_mode = on master_slave_mode = on master_slave_sub_mode = 'stream' connection_cache = on max_pool = 4

load_balance_mode控制select查询在节点间分发,master_slave_mode与master_slave_sub_mode='stream'共同声明底层是流复制架构。这两个参数必须同时开启,否则pgpool不知道该把写请求固定发到主库。

读写分离的权重由backend_weight控制,双节点都设为1表示读请求平均分发。如果备库硬件配置较差或承载其他业务,可将备库权重调到0或0.5。

4.5 watchdog与虚拟IP配置

pgpool自带的watchdog机制负责HA管理,不需要额外安装keepalived。watchdog通过心跳连接判断对方节点是否存活,主动节点持有delegate_IP即虚拟IP。客户端始终连接虚拟IP,主库故障时VIP自动漂移到备库pgpool节点。

主节点与备节点的watchdog配置差异在于wd_hostname分别填写自己节点的实际IP。以下参数在主备节点上配置相同:

delegate_IP = '192.168.10.100' wd_lifecheck_method = 'heartbeat' wd_heartbeat_port = 9694 wd_life_point = 3 wd_lifecheck_interval = 2 wd_heartbeat_keepalive = 2 wd_heartbeat_deadtime = 30

wd_lifecheck_method用heartbeat而不用query,是因为query方式依赖数据库查询,在数据库资源紧张或锁等待时会误判pgpool节点死亡。heartbeat方式走独立的UDP端口,可靠性更高。wd_heartbeat_deadtime=30表示30秒内收不到心跳即判定对方死亡,配合wd_life_point=3和wd_lifecheck_interval=2,正常情况下约6秒可以探测出异常。

if_cmd_path = '/sbin' if_up_cmd = 'ip addr add $_IP_$/32 dev eth0 label eth0:0' if_down_cmd = 'ip addr del $_IP_$/32 dev eth0 label eth0:0'

虚拟IP的绑定脚本在生产环境需要注意网卡名称。RHEL 7.5之后的网卡命名可能是ens192而非eth0,必须把dev eth0改成实际网卡名,否则VIP绑定失败或绑到错误接口。我第一套环境在这里折腾了小半天,接口写错之后VIP不出现,客户端完全连不上。

4.6 健康检查与流复制监控

pgpool对后端数据库节点的监控分两个层面:health_check检查数据库进程是否可连接,sr_check检查流复制是否正常。两个都要配置。

health_check_period = 10 health_check_timeout = 5 health_check_user = 'postgres' health_check_password = 'Postgres@123456' health_check_max_retries = 3 sr_check_period = 10 sr_check_user = 'repluser' sr_check_password = 'Repl@123456'

sr_check需要用户具备复制权限或至少能查询pg_stat_replication视图,直接用流复制用户repluser即可。如果sr_check配置错误,pgpool可能误判备库延迟,把备库标记为down状态,这时读写分离会失效。

4.7 failover脚本与自动切换

failover_command是故障切换时执行的脚本,pgpool传入多个占位符参数。4.1.1版本支持的参数包括:%H新主节点主机名、%h旧主节点主机名、%P旧主节点编号等。failover脚本做的事情必须完整,否则切换后业务不可用。

编写failover脚本时,我遵循以下逻辑顺序:先判断新主是否可达,然后在新主上清理备库标记,再将旧主设为备库并重建流复制链路。

#!/bin/bash # failover.sh - pgpool自动切换脚本 # 参数顺序: 新主host 旧主host 旧主节点ID NEW_PRIMARY_HOST=$1 OLD_PRIMARY_ID=$3

实际使用时脚本体量远不止这几行,还需要包含SSH免密连接、standby.signal处理、pgpool节点重新attach等操作。文档在原方案中给出了failover文件配置的说明,实践时建议先手工模拟一遍脚本在主备切换过程中的每一步,再挂到pgpool下自动执行。

4.8 pcp.conf、pool_passwd与pool_hba认证配置

pgpool的pcp管理端口(9898)需要独立的认证配置。pg_md5命令生成的是pgpool专用的MD5格式密码,不是PG数据库用户密码,不能混用。

echo "postgres:$(pg_md5 Pcp@123456)" > /usr/local/pgpool/etc/pcp.conf chown postgres:postgres /usr/local/pgpool/etc/pcp.conf chmod 600 /usr/local/pgpool/etc/pcp.conf

pool_passwd文件用于应用通过pgpool连接数据库时的密码校验,生成方式同样是pg_md5:

pg_md5 -m -u postgres -p # 提示输入数据库用户postgres的实际密码

pool_hba.conf是pgpool层面的访问控制,与PG的pg_hba.conf是两个不同的文件。很多人在排错时只检查PG的pg_hba.conf,忽略了pool_hba.conf中同样存在白名单限制。

host all all 0.0.0.0/0 md5

生产环境按实际客户端网段替换0.0.0.0/0。同时注意pool_hba.conf中的认证方式要与pool_passwd对应,用md5就要在pgpool.conf中配置enable_pool_hba=on。

4.9 启动pgpool与连接测试

主备节点分别启动pgpool,启动前检查配置文件语法是否有误。4.1.1版本支持用pgpool自带的配置文件检查方式确认参数是否合法。

pgpool -f /usr/local/pgpool/etc/pgpool.conf -n > /var/log/pgpool/pgpool.log 2>&1 &

-n参数让pgpool以前台方式运行,日志输出到指定文件。首次启动建议这样做,观察日志没有异常后再改为后台守护进程方式。

连接测试时先确认pgpool进程在运行、后端节点状态正常。使用show pool_nodes命令查看pgpool视角下的节点状态:

psql -h 192.168.10.100 -p 9999 -U postgres -d postgres -c "show pool_nodes;"

node 0和node 1的状态都应为up。pgpool集群中主节点显示为primary,备库显示为standby。如果备库状态显示down,检查sr_check配置和PG的流复制状态。

虚拟IP验证可以通过ip addr在pgpool主节点上查看eth0:0网卡是否存在,辅助网卡上的IP应与delegate_IP一致。

5. 常见问题排查:五个高可用翻车现场的处理笔记

这一章是排错经验的汇总,每条都是生产环境里真实出现过的案例,现象、原因、解决方式拆开写,照着排查就行。

5.1 no pg_hba.conf entry for host

现象:应用或备库通过pgpool连接时报no pg_hba.conf entry for host "192.168.x.x",同时伴随fe_sendauth: no password supplied。

原因:PG主库的pg_hba.conf中没有添加对应客户端网段的访问记录,或者添加后没有reload。另一个容易忽略的点是pgpool的pool_hba.conf也有同样的限制,两处都要放行。

解决:在主库的pg_hba.conf中添加客户端网段记录,执行pg_ctl reload;再检查pgpool的pool_hba.conf,如有限制则同步修改并重启pgpool。我处理过一个案例是开发网段在pg_hba.conf里加的是localhost,应用服务器一换IP就报这个错,这种问题最有效的排查方式是先看主库日志,日志会明确指出被拒绝的连接来源IP和使用的数据库用户。

5.2 all backend nodes are down

现象:通过pgpool连接数据库报all backend nodes are down,应用完全无法访问。

原因:pgpool的健康检查失败,可能的原因包括health_check_user密码错误、PG主库5432端口无法访问、备库没有启动流复制导致连接异常。pgpool几乎不提供任何中间过程的说明,排错基本靠日志。

解决:先tail -f /var/log/pgpool/pgpool.log查看健康检查失败的具体原因,再用psql -h 192.168.10.11 -p 5432 -U postgres直连两个后端确认数据库本身可用。如果直连正常但pgpool仍然报down,重点检查health_check_password是否与PG实际密码匹配,以及pg_hba.conf中host all all的记录是否正确。这套环境里我遇到过密码特殊字符被pgpool.conf解析出错的问题,排查了很长时间,后来在密码两端加单引号解决。

5.3 备库没有同步数据

现象:备库查询数据与主库不一致,主库pg_stat_replication视图为空。

原因:最常见的是备库的standby.signal不存在,或者primary_conninfo配置错误。PG 12.x用standby.signal替代recovery.conf,老版本迁移照搬的配置在新版本里不生效。

解决:检查备库数据目录中是否存在standby.signal,不存在则touch /data/postgresql/data/standby.signal;检查postgresql.conf中的primary_conninfo是否包含密码参数。然后重启备库,看日志中的streaming replication started是否出现。这里需要特别点名:-R参数生成的primary_conninfo不会写入密码,这是初装时最容易漏的环节。从那以后我每次用pg_basebackup部署备库后,都会强制检查一次primary_conninfo中的密码字段。

5.4 两台pgpool节点同时持有虚拟IP

现象:两台服务器上都能看到虚拟IP 192.168.10.100,客户端连接到不同的pgpool节点,写入请求可能落到旧主库上。

原因:watchdog心跳网络不通,或者UDP端口9694在防火墙被拦截。两个节点都认为对方已死,各自把自己提升为active状态,同时绑定VIP。这是双节点HA最危险的场景,处理不好会出现双主写入。

解决:确保两台机器之间的9694端口互通,nc -uv 192.168.10.12 9694测试心跳端口;检查防火墙是否放行watchdog使用的协议。若已经出现双VIP,先禁止业务写入,再手动摘除备节点的VIP地址,让主节点重新独占。之后调大wd_heartbeat_deadtime,避免网络抖动引起误判。

5.5 failover后旧主自动恢复导致双主

现象:主库故障切换后,备库被提升为新主,但旧主库在恢复过程中以主库身份重新加入pgpool节点列表,应用写入出现路由混乱。

原因:failover脚本没有处理好旧主节点恢复时的角色转换。旧主库恢复后,如果没有把standby.signal放回数据目录,它不会自动以备库身份启动,而是以独立主库身份运行。

解决:在failover脚本中必须包含旧主角色的重置逻辑。旧主一旦恢复,需要执行pg_ctl promote的反向操作,即重新创建standby.signal文件并重启PG实例,让它作为新主的备库加入。同时调用pcp_attach_node命令把旧主重新挂回pgpool节点列表。这个场景我建议在测试环境完整模拟几次:停主库、切换、旧主恢复、观察节点状态,脚本逻辑全部验证通过后再上生产。

6. 装完怎么验证跑通:Failover演练与pg_rman备份恢复

配置完成不代表万事大吉,故障切换和备份恢复这两个环节必须实际演练,否则整套架构只是纸面高可用。

6.1 主库停服测试:观察VIP漂移与读写切换

先确认pgpool节点状态正常,再模拟主库故障:

-- 在pgpool节点查看后端状态 psql -h 192.168.10.100 -p 9999 -U postgres -d postgres -c "show pool_nodes;"
# 在主库节点停止PG pg_ctl -D /data/postgresql/data -m fast stop

观察pgpool日志中failover触发记录,等待数秒后再次执行show pool_nodes,node 1状态应变为primary,node 0显示为down或standby。检查虚拟IP是否已漂移到备库节点:ip addr | grep 192.168.10.100。然后在应用连接串不变的情况下,通过虚拟IP执行写入操作验证新主可写。

6.2 pgpool节点自身故障的切换测试

PG主库故障时VIP是否漂移,取决于pgpool的watchdog怎样处理。如果只是PG实例挂掉但pgpool进程存活,VIP不会漂移,pgpool会执行failover脚本提升备库;如果pgpool进程本身挂掉,VIP才会漂移到备用pgpool节点。这个区别很多人会混淆,测试时要分别演练两个故障场景。

# 停止pgpool主节点的进程 kill -9 $(pgrep pgpool)

然后观察备节点是否接管VIP并在备节点上重新响应对9999端口的连接。测试成功后恢复节点,主备pgpool再次进入watchdog协商状态。

6.3 pg_rman备份与恢复验证

pg_rman的用途是离线备份。归档模式开启后,数据库产生的WAL日志会被持续归档到备份目录,配合定期全量备份,可以在误操作时恢复到任意时间点。安装和配置方式在文档中有明确步骤,这里重点讲验证。

# 初始化备份目录 pg_rman init -B /data/pgbackup # 执行全量备份 pg_rman backup -B /data/pgbackup -b full -C -Z -h 127.0.0.1 -p 5432 -U postgres # 验证备份完整性 pg_rman validate -B /data/pgbackup

-C表示备份后切换WAL日志,-Z启用压缩归档。备份完成后,把数据恢复到一台测试机上,确认数据库可正常启动且数据完整。定期检查pg_rman show -B /data/pgbackup的输出,确保最新一次备份状态为OK。

整套方案的验证不是一次性的。故障切换演练必须纳入日常巡检,备份恢复演练也要定期执行。从那以后我每次搭建完PG高可用集群,都会强制把所有故障切换场景和备份恢复流程完整走一遍,确认数据能找回才交付。这套方法费时间,但值得,希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进