SkillAgentSearch skills...

Pha4pgsql

Pacemaker High Availability for PostgreSQL

Install / Use

/learn @ChenHuajun/Pha4pgsql
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Pacemaker High Availability for PostgreSQL

简介

原生的基于Pacemaker+Corosync搭建PostgreSQL流复制HA集群配置和使用都比较复杂,因此封装了一些常用的集群配置和操作命令,目的在于简化集群的部署和使用。同时对Resource Agent 4.2.0的pgsql RA进行了增强,引入分布式锁服务,防止双节点集群出现脑裂,并确保同步复制下failover后数据不丢失。 但是,你还是必须了解Pacemaker的相关概念和基本操作,用于解决封装脚本处理不了的问题。

本工具已停止更新,建议优先使用其他PG HA工具,比如Patroni,可参考 基于Patroni的PostgreSQL高可用环境部署

功能特性

  1. 秒级故障转移
  2. 支持双节点集群和多节点集群
  3. 支持同步复制和异步复制
  4. 同步复制下failover零数据丢失
  5. 提供读写VIP和只读VIP,集群的拓扑结构对应用透明

基本架构和原理

  1. Pacemaker + Corosync作为集群基础软件,Corosync负责集群通信和成员关系管理,Pacemaker负责资源管理。
  2. 集群用到资源包括PostgreSQL和VIP等,PostgreSQL对应的Resource Agent(RA)为expgsql,expgsql负责实施PostgreSQL的起停,监视,failover等操作。
  3. 集群初始启动时expgsql通过比较所有节点的xlog位置,找出xlog最新的节点作为Master,其它节点作为Slave通过读写VIP连接到Master上进行WAL复制。
  4. 集群启动后expgsql不断监视PostgreSQL的健康状况,当expgsql发现PostgreSQL资源故障时报告给Pacemaker,由Pacemaker实施相应动作。
    • 如果是PostgreSQL进程故障,原地重启PostgreSQL,并且该节点上的fail-count加1。
    • fail-count累加到3时不再分配PostgreSQL资源到这个节点。如果该节点为Master,会提升一个Slave为Master,即发起failover。
  5. Corosync发现节点故障(主机或网络故障)时,Pacemaker也根据情况实施相应动作。
    • 对多节点集群,未包含过半节点成员的分区将主动释放本分区内的所有资源,包括PostgreSQL和VIP。
    • 合法的分区中如果没有Master,Pacemaker会提升一个Slave为Master,即发起failover。
  6. Master上的expgsql会不断监视Slave的复制健康状况,同步复制下会选定一个Slave作为同步Slave。
  7. 当同步Slave出现故障时,Master上的expgsql会临时将同步复制切换到异步复制,防止Master上的写操作被hang住。如果故障Slave恢复或存在另一个健康的Slave,再切换到同步复制。
  8. 为防止集群分区后,Slave升级为新Master而旧Master切换到异步复制导致脑裂和数据双写,引入分布式锁服务进行仲裁。Slave升级为新Master和旧Master切换到异步复制前必须先取得锁,避免这两件事同时发生。失去锁的Master会主动停止PostgreSQL进程,防止出现双主。
  9. 如果分布锁服务发生故障而所有PostgreSQL节点都是健康的,expgsql会忽视锁服务,即不影响集群服务。但在分布锁服务故障期间,Master发生节点故障(注意区分节点故障和资源故障),集群将无法正常failover。
  10. 同步复制下只有同步Slave才有资格成为候选Master,加上有分布式锁的防护,可以确保failover后数据不丢失。
  11. 集群初始启动和每次failover时通过pg_ctl promote提升Slave为Master并使时间线加1,同时记录Master节点名,时间线和切换时的xlog位置到集群CIB。
  12. 集群重启时根据集群CIB中记录的信息确定Master节点,并保持时间线不变。
  13. expgsql启动PostgreSQL前会检查该节点的时间线和xlog,如果和集群CIB中记录的信息有冲突,将报错。需要人工通过cls_repair_by_pg_rewind等手段修复。
  14. 读写VIP和Master节点绑定,只读VIP和其中一个Slave绑定,应用只需访问VIP,无需关心具体访问哪个节点。

集群操作命令一览

  1. cls_start
    启动集群

  2. cls_stop
    停止集群

  3. cls_online_switch
    在线主从切换,对多节点集群当前不支持指定新Master。在多节点的同步复制下,只有pgsql-data-status值为“STREAMING|SYNC”的节点,即同步复制节点可以作为候选master。如果希望指定其它节点作为新的master,可以在master上执行下面的操作,然后等待pgsql-data-status更新。

     su - postgres
     echo "synchronous_standby_names = 'node3'" > /var/lib/pgsql/tmp/rep_mode.conf
     pg_ctl -D /home/postgresql/data reload
     exit
    
  4. cls_master
    输出当前Master节点名

  5. cls_status
    显示集群状态

  6. cls_cleanup
    清除资源状态和fail-count。在某个节点上资源失败次数(fail-count)超过3次Pacemaker将不再分配该资源到此节点,人工修复故障后需要调用cleanup让Pacemkaer重新尝试启动资源。

  7. cls_reset_master [master]
    设置pgsql_REPL_INFO使指定的节点成为Master;如未指定Master,则清除pgsql_REPL_INFO让Pacemaker重新在所有节点中选出xlog位置最新的节点作为Master。仅用于集群中没有任何节点满足Master条件情况下的紧急修复。

  8. cls_repair_by_pg_rewind 通过pg_rewind修复当前节点,主要用于旧Master的修复,回退超出时间线分叉点的那部分更新,并和新Master建立复制关系。pg_rewind仅在PostgreSQL 9.5以上版本提供

  9. cls_rebuild_slave
    通过pg_basebackup在当前节点重建Slave。执行该命令前需要停止当前节点上的PostgreSQL进程并清空旧的数据目录。

  10. cls_maintenance
    切换集群到维护模式使所有资源脱离Pacemaker的控制。当需要重启Pacemaker和Corosync又不能停止PostgreSQL服务时,可以先调用这个命令,Pacemaker和Corosync重启完成后再调用用cls_unmaintenance恢复为普通模式。

  11. cls_unmaintenance
    从维护模式恢复到普通模式。

  12. cls_maintenance_node <nodename> 使节点进入维护模式。维护模式和unmanage resource相比的区别是会取消monitor,比unmanage更彻底。

  13. cls_unmaintenance_node <nodename> 解除节点的维护模式。

  14. cls_standby_node <nodename>
    释放某节点上所有资源。可用于特定节点的维护,比如升级。

  15. cls_unstandby_node <nodename>
    恢复cls_standby_node产生的节点standby状态。

以上命令必须以root用户执行

依赖软件

  • pacemaker
  • corosync
  • pcs
  • ipvsadm

支持的PostgreSQL版本

  • PostgreSQL 9.6
  • PostgreSQL 10
  • PostgreSQL 11

安装

安装过程以在以下环境下部署双节点HA集群为例说明。
多节点的安装示例请参考:基于Pacemaker的PostgreSQL一主多从读负载均衡集群搭建

  • OS:CentOS 7.1
  • 节点1主机名:node1
  • 节点2主机名:node2
  • writer_vip:192.168.41.136
  • reader_vip:192.168.41.137
  • 用作分布式锁服务的PostgreSQL的连接字符串:"host=node3 port=5439 dbname=postgres user=postgres"

Linux集群环境安装与配置

环境准备

  1. 所有节点设置时钟同步

     cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
     ntpdate time.windows.com && hwclock -w  
    
  2. 所有节点设置独立的主机名(node1,node2)

     hostnamectl set-hostname node1
    
  3. 设置对所有节点的域名解析(修改/etc/hosts)

  4. 所有节点间设置SSH互信

禁用防火墙

在所有节点执行:

setenforce 0
sed -i.bak "s/SELINUX=enforcing/SELINUX=permissive/g" /etc/selinux/config
systemctl disable firewalld.service
systemctl stop firewalld.service
iptables -F

如果开启防火墙需要开放postgres,pcsd和corosync的端口。

  • postgres:5432/tcp
  • pcsd:2224/tcp
  • corosync:5405/udp

安装Pacemaker和Corosync及相关软件包

在所有节点执行:

yum install -y pacemaker corosync pcs ipvsadm

注:如果OS自带的Pacemaker比较旧,建议下载新版的。之前在Pacemaker 1.1.7上遇到了不少Bug,因此不建议使用这个版本或更老的版本。配置LVS(使用muti_with_lvs.pcs.template模板)支持需要安装ipvsadm

启用pcsd服务

在所有节点执行:

systemctl start pcsd.service
systemctl enable pcsd.service

设置hacluster用户密码

在所有节点执行:

echo hacluster | passwd hacluster --stdin

集群认证

在任何一个节点上执行:

pcs cluster auth -u hacluster -p hacluster node1 node2

同步配置

在任何一个节点上执行:

pcs cluster setup --last_man_standing=1 --name pgcluster node1 node2

启动集群

在任何一个节点上执行:

pcs cluster start --all

安装和配置PostgreSQL

安装PostgreSQL

在所有节点执行:

yum install postgresql-server

OS自带的PostgreSQL往往比较旧,可参考http://www.postgresql.org/download/linux/ ,安装最新版PostgreSQL.

创建主数据库

在node1节点执行:

  1. 创建数据目录

     mkdir -p /data/postgresql/data
     chown -R postgres:postgres /data/postgresql/
     chmod 0700 /data/postgresql/data
    
  2. 初始化db

     su - postgres
     initdb -D /data/postgresql/data/
    
  3. 修改postgresql.conf

     listen_addresses = '*'
     wal_level = hot_standby
     wal_log_hints = on
     synchronous_commit = on
     max_wal_senders=5
     wal_keep_segments = 32
     hot_standby = on
     wal_sender_timeout = 5000
     wal_receiver_status_interval = 2
     max_standby_streaming_delay = -1
     max_standby_archive_delay = -1
     restart_after_crash = off
     hot_standby_feedback = on
    

    注:PostgreSQL9.5以上版本设置"wal_log_hints = on"可以使用pg_rewind修复旧Master。

  4. 修改pg_hba.conf

     local   all                 all                              trust
     host    all                 all     192.168.41.0/24          md5
     host    replication         all     192.168.41.0/24          md5
    
  5. 启动postgres

     pg_ctl -D /data/postgresql/data/ start
    
  6. 创建复制用户

     createuser --login --replication replication -P
    

    9.5以上版本如需要支持pg_rewind,需加上“-s”选项。

     createuser --login --replication replication -P -s
    

创建备数据库

在node2节点执行:

  1. 创建数据目录

     mkdir -p /data/postgresql/data
     chown -R postgres:postgres /data/postgresql/
     chmod 0700 /data/postgresql/data
    
  2. 创建基础备份

     su - postgres
     pg_basebackup -h node1 -U replication -D /data/postgresql/data/ -X stream -P
    

停止PostgreSQL服务

在node1上执行:

	pg_ctl -D /data/postgresql/data/ stop

配置分布式锁服务

分布式锁服务的作用是防止双节点集群出现脑裂。当网络发生故障形成分区时,备可能会被提升为主,同时旧主会将同步复制切换到异步复制,这可能导致数据丢失。通过分布式锁服务可以确保新主的提升和旧主的切换到异步复制同时只能有一个成功。

分布式锁服务通过HA集群外部的另外一个PostgreSQL服务实现。需要事先创建锁表。

create table if not exists distlock(lockname text primary key,owner text not null,ts timestamptz not null,expired_time interval not null);

可选地,可以创建锁的历史表,每次锁的owner变更(主从角色切换)都会记录到历史表(distlock_history)中。

create table if not exists distlock_history(id serial primary key,lockname text not null,owner text not null,ts timestamptz not null,expired_time interval not null);

CREATE OR REPLACE FUNCTION distlock_log_update() RETURNS trigger AS $$
    BEGIN
    
        IF TG_OP = 'INSERT' or NEW.owner <> OLD.owner THEN
            INSERT INTO distlock_history(lockname, owner, ts, expired_time) values(NEW.lockname, NEW.owner, NEW.ts, NEW.expired_time);
        END IF;
        RETURN NEW;
    END;
$$ LANGUAGE plpgsql;


DROP TRIGGER IF EXISTS distlock_log_update ON distlock;

CREATE TRIGGER distlock_log_update AFTER INSERT OR UPDATE ON distlock
    FOR EACH ROW EXECUTE PROCEDURE distlock_log_update();

安装和配置pha4pgsql

在任意一个节点上执行:

  1. 下载pha4pgsql

     git clone git://github.com/Chenhuajun/pha4pgsql.git
    
  2. 编辑config.ini

     pcs_template=dual.pcs.template
     OCF_ROOT=/usr/lib/ocf
     RESOURCE_LIST="msPostgresql vip-master vip-slave"
     pha4pgsql_dir=/opt/pha4pgsql
     writer_vip=192.168.41.136
     reader_vip=192.168.41.137
     node1=node1
     node2=node2
     vip_nic=eno33554984
     vip_cidr_netmask=24
     pgsql_pgctl=/usr/bin/pg_ctl
     pgsql_psql=/usr/bin/psql
     pgsql_pgdata=/data/postgresql/data
     pgsql_pgdata=5432
     pgsql_restore_command=""
     pgsql_rep_mode=sync
     pgsql_repuser=replication
     pgsql_reppassord=replication
     pgsql_enable_distlock=true
     pgsql_distlock_psql_cmd='/usr/bin/psql \\"host=node3 port=5439 dbname=postgres user=postgres connect_timeout=5\\"'
     pgsql_distlock_lockname=pgsql_cls1
    

    需要根据实际环境修改上面的参数。当多个集群使用锁服务时,确保每个集群的pgsql_distlock_lockname值必须是唯一的。

    template目录下有预定义的参数模板。

    • config_dual.ini.sample
      双节点参数模板,通过同步复制和分布式锁仲裁防止脑裂
    • config_muti.ini.sample 多节点参数模板,通过no-quorum-policy="stop"防止脑裂
    • config_muti_with_lvs.ini.sample 多节点参数模板,并引入LVS做读负载均衡
  3. 安装pha4pgsql

     sh install.sh
    

    这一步会拷贝需要的脚本到本地和远程机器上,并生成集群的资源配置文件。

     [root@node1 pha4pgsql]# cat config.pcs 
     
     pcs cluster cib pgsql_cfg
     
     pcs -f pgsql_cfg property set no-quorum-policy="ignore"
     pcs -f pgsql_cfg property set stonith-enabled="false"
     pcs -f pgsql_cfg resource defaults resource-stickiness="1"
     pcs -f pgsql_cfg resource defaults migration-threshold="10"
     
     pcs -f pgsql_cfg resource create vip-master IPaddr2 \
        ip="192.168.41.136" \
        nic="eno33554984" \
        cidr_netmask="24" \
        op start   timeout="60s" interval="0s"  on-fail="restart" \
        op mo
    
View on GitHub
GitHub Stars62
CategoryData
Updated28d ago
Forks30

Languages

Shell

Security Score

95/100

Audited on Feb 28, 2026

No findings