ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

PostgreSQL双节点高可用:流复制、pgpool与pg_rman

PostgreSQL双节点高可用:流复制、pgpool与pg_rman

简介:面向 PostgreSQL 运维与架构人员的高可用方案文档,聚焦流复制与 pgpool-II 的组合部署,覆盖主备库搭建、WAL 日志实时同步、同步与异步复制取舍、只读请求分流、读写分离及故障切换等核心问题。压缩包仅含 1 个 docx 文件,大小约 773KB,内容按方案介绍、实践环境、客户环境准备、资源调整等章节展开,便于按部署阶段快速查阅。文档涉及连接池、复制、负载均衡、连接数限制与 pg_rman 备份,并梳理主库 wal_level、synchronous_commit 配置、备库初始化、pgpool-II 参数设置和启动测试思路。已有 471 人学习,适合需要实施主从复制与高可用架构的中级数据库从业者作为配置参考和排错索引。

1. 双节点高可用不是“装完主从就收工”:这份方案到底解决什么

这套 PostgreSQL 主从流复制加 pgpool-II 的高可用方案,第一次翻目录会觉得像标准实施手册:流复制、连接池、读写分离、failover、pg_rman 备份,一条线全串起来。真正落地时,难点不在装软件,而在版本差异、切换脚本和备份恢复的闭环。它适合正在 RHEL/CentOS 上维护 PostgreSQL 10 或 12、想把单机库改成双节点高可用,又不想引入过重中间件的团队;也适合需要内网离线部署、手里只有 rpm 包和几台 Linux 机器的运维。方案的核心不是某个参数,而是把“实时同步、只读分流、故障切换、离线恢复”四段拼成一条能反复演练的链路。流复制负责数据不丢,pgpool 负责连接入口和故障检测,pg_rman 负责误操作后的后悔药,三者缺一段,高可用就只是纸面高可用。

2. 版本与环境先把路铺平:RHEL/CentOS 下的依赖、用户和内核参数

2.1 版本组合和组件分工:先确认 PostgreSQL 与 pgpool 对得上

方案里给了新旧两套环境,旧环境是 CentOS 6.5、PostgreSQL 10.3、pgpool-II 3.6.14;新环境是 CentOS 7.5、PostgreSQL 12.2、pgpool-II 4.1.1。这个版本跨度不是随便写的,PostgreSQL 12 取消了recovery.conf,pgpool 4.x 又把集群模式参数改成了backend_clustering_mode,拿旧配置直接套新版本,备库和 pgpool 都会起不来。

组件旧环境新环境落地注意点
PostgreSQL10.312.212 开始用standby.signal,不再读recovery.conf
pgpool-II3.6.144.1.14.x 用backend_clustering_mode,3.x 用master_slave_mode
pg_rman与 PostgreSQL 大版本匹配与 PostgreSQL 大版本匹配不要跨大版本混用备份工具
操作系统CentOS 6.5CentOS 7.5内网离线源、依赖包和 cache 要提前准备

组件分工也要先分清:PostgreSQL 流复制只做数据同步,备库默认只读;pgpool-II 站在数据库前面,做连接池、读写分离、健康检查和 VIP 漂移;pg_rman 做的是离线备份和按时间点恢复,不是替代流复制。常见误区是把 pgpool 当成“自动故障转移数据库”,实际上 pgpool 只负责发现后端挂了并执行failover_command,真正的备库提升要在脚本里做。方案选流复制而不是文件归档传送,是因为流复制在 master 一产生 WAL 就通过 TCP 传给 standby,延迟比“写完一个 WAL 文件再拷贝”低得多;选 pgpool 而不是应用层双写,是因为连接池和只读分流对应用侵入小,改一个连接端口就能接进来。

2.2 操作系统层六件事:防火墙、SELinux、hosts、时钟、sysctl、limits

方案把操作系统准备放在安装 PostgreSQL 之前,这个顺序是对的。很多“主备连不上”最后查出来不是数据库参数,而是防火墙没放行、SELinux 拦了 pgpool 绑 VIP,或者两台机器时间差太大导致日志和切换判断对不上。内网环境可以简化,但简化不等于跳过。

# CentOS 7 示例:内网方案文档为了省事会直接关防火墙和 SELinux systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config # 主机名和 hosts 必须能互相解析,主机名不要带下划线 cat >> /etc/hosts <<'EOF' 192.168.56.11 pg-master 192.168.56.12 pg-standby 192.168.56.13 pgpool-vip EOF # 时钟同步,主备时间差控制在秒级以内 systemctl enable chronyd systemctl start chronyd chronyc sources -v

上面这段是方案里“关闭防火墙、关闭 selinux、网络配置、配置 hosts、主备节点时钟同步”的合并写法。生产环境不建议永久关闭防火墙,更稳的做法是只放行 PostgreSQL 5432、pgpool 9999、pcp 9898、SSH 22 以及 watchdog 心跳端口;SELinux 至少设成 permissive,或者按 pgpool 的启动脚本和 VIP 绑定动作单独放行。/etc/hosts里三个名字要能互相ping通,后面primary_conninfo、backend_hostname、failover_command都靠主机名或 IP 定位,别让一台机器用 IP、另一台用主机名,排错时会多花很多时间。

sysctl 和 limits 是方案里容易被跳过的部分。PostgreSQL 需要足够的共享内存和信号量,pgpool 绑定非本地 VIP 需要ip_nonlocal_bind,连接数上来后nofile不够会直接报“too many open files”。

# /etc/sysctl.d/99-pgpool.conf cat > /etc/sysctl.d/99-pgpool.conf <<'EOF' kernel.shmmax = 68719476736 kernel.shmall = 4294967296 kernel.sem = 250 32000 100 128 vm.swappiness = 10 net.ipv4.ip_nonlocal_bind = 1 EOF sysctl --system # /etc/security/limits.d/20-postgres.conf cat > /etc/security/limits.d/20-postgres.conf <<'EOF' postgres soft nproc 2048 postgres hard nproc 2048 postgres soft nofile 65536 postgres hard nofile 65536 EOF

kernel.shmmax和kernel.shmall按机器内存调整,不要照抄成大值把系统撑爆;kernel.sem是信号量数组,PostgreSQL 并行查询和连接数高时会用到;vm.swappiness=10是让数据库尽量不换页;net.ipv4.ip_nonlocal_bind=1允许 pgpool 在 VIP 还没漂过来时绑定地址,watchdog 切换时更顺。limits里的nofile要大于max_connections加上 pgpool 连接池和后端进程的开销,改完用su - postgres -c 'ulimit -n'验证,别只改文件不验证。

2.3 目录、用户与权限:安装路径和后续脚本的约定

方案里创建postgres用户、配置安装文件夹、修改文件夹权限,这些动作看起来琐碎,但后面所有脚本都依赖这套路径约定。建议统一成:PostgreSQL 装在/opt/pgsql,数据目录/data/pgdata,归档目录/data/pg_archive,pg_rman 备份目录/data/pg_backup,pgpool 工作目录/var/lib/pgpool,日志目录/var/log/pgpool。路径一旦定下来,postgresql.conf、pgpool.conf、备份脚本和附件里的安装脚本都按这个找,后期换机器也容易复制。

# 创建 postgres 用户和目录,root 执行 groupadd -g 1001 postgres useradd -g postgres -u 1001 -m -s /bin/bash postgres passwd postgres mkdir -p /opt/pgsql /data/pgdata /data/pg_archive /data/pg_backup mkdir -p /var/lib/pgpool /var/log/pgpool chown -R postgres:postgres /opt/pgsql /data /var/lib/pgpool /var/log/pgpool chmod 700 /data/pgdata

这里的关键是权限:/data/pgdata必须 700,属主是postgres,不能用 root 跑initdb,否则后面pg_ctl start会因为数据目录属主不对拒绝启动。/data/pg_archive和/data/pg_backup可以给 750,但归档目录要允许 PostgreSQL 进程写入。pgpool 如果和 PostgreSQL 共用postgres用户启动,/var/lib/pgpool和/var/log/pgpool也要归postgres;如果单独建pgpool用户,就要保证它能读pgpool.conf、写运行目录,并且能通过 SSH 免密到备库执行提升命令。方案附件里的环境准备脚本和安装脚本,本质上就是把这些路径、用户、权限和依赖包固定下来,减少手工漏项。

3. PostgreSQL 流复制:从 initdb 到 walreceiver 跑通

3.1 主库参数:wal_level、max_wal_senders 与同步复制开关

PostgreSQL 安装可以源码编译,也可以用内网 rpm,路径按/opt/pgsql走。依赖包常见的是readline-devel、zlib-devel、openssl-devel、libxml2-devel,编译参数--prefix=/opt/pgsql。装完先initdb -D /data/pgdata -E UTF8 --locale=C,再改postgresql.conf。流复制的核心参数不多,但每一个都影响后面能不能跑通。

# postgresql.conf 片段,PostgreSQL 10/12 通用,按内存和磁盘调整 listen_addresses = '*' port = 5432 wal_level = replica max_wal_senders = 10 wal_keep_segments = 64 hot_standby = on archive_mode = on archive_command = 'test ! -f /data/pg_archive/%f && cp %p /data/pg_archive/%f' # 同步复制先别开,等备库跑通、压测后再开 synchronous_commit = local # synchronous_standby_names = 'standby1'

wal_level=replica是流复制的最低要求,记录足够多的 WAL 给备库重放;max_wal_senders要大于备库数量加备份连接数,只有一个备库时 10 足够,后面加级联备库或 pg_basebackup 并发要往上调;wal_keep_segments是主库保留的 WAL 段数,备库落后太多时防止主库把还没传过去的 WAL 删掉,小库 64 够用,写入量大就加到 256 或者用复制槽;hot_standby=on让备库可以接受只读查询,这是后面 pgpool 读写分离的前提;archive_mode=on和archive_command是给 pg_rman 做归档备份用的,归档目录要和数据目录分开。synchronous_commit先设local,意思是主库本地写完就提交,不等备库确认,等主从稳定后再改成on并配synchronous_standby_names,否则备库一挂主库写事务会卡住。

参数改完重启主库:pg_ctl start -D /data/pgdata -l /data/pgdata/startup.log。启动日志里看到database system is ready to accept connections才算起库成功,不要只看命令返回值。listen_addresses改成*后要确认pg_hba.conf也

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

RELATED READING

延伸阅读

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