Pha4pgsql
Pacemaker High Availability for PostgreSQL
Install / Use
/learn @ChenHuajun/Pha4pgsqlREADME
Pacemaker High Availability for PostgreSQL
简介
原生的基于Pacemaker+Corosync搭建PostgreSQL流复制HA集群配置和使用都比较复杂,因此封装了一些常用的集群配置和操作命令,目的在于简化集群的部署和使用。同时对Resource Agent 4.2.0的pgsql RA进行了增强,引入分布式锁服务,防止双节点集群出现脑裂,并确保同步复制下failover后数据不丢失。 但是,你还是必须了解Pacemaker的相关概念和基本操作,用于解决封装脚本处理不了的问题。
本工具已停止更新,建议优先使用其他PG HA工具,比如Patroni,可参考 基于Patroni的PostgreSQL高可用环境部署
功能特性
- 秒级故障转移
- 支持双节点集群和多节点集群
- 支持同步复制和异步复制
- 同步复制下failover零数据丢失
- 提供读写VIP和只读VIP,集群的拓扑结构对应用透明
基本架构和原理
- Pacemaker + Corosync作为集群基础软件,Corosync负责集群通信和成员关系管理,Pacemaker负责资源管理。
- 集群用到资源包括PostgreSQL和VIP等,PostgreSQL对应的Resource Agent(RA)为expgsql,expgsql负责实施PostgreSQL的起停,监视,failover等操作。
- 集群初始启动时expgsql通过比较所有节点的xlog位置,找出xlog最新的节点作为Master,其它节点作为Slave通过读写VIP连接到Master上进行WAL复制。
- 集群启动后expgsql不断监视PostgreSQL的健康状况,当expgsql发现PostgreSQL资源故障时报告给Pacemaker,由Pacemaker实施相应动作。
- 如果是PostgreSQL进程故障,原地重启PostgreSQL,并且该节点上的fail-count加1。
- fail-count累加到3时不再分配PostgreSQL资源到这个节点。如果该节点为Master,会提升一个Slave为Master,即发起failover。
- Corosync发现节点故障(主机或网络故障)时,Pacemaker也根据情况实施相应动作。
- 对多节点集群,未包含过半节点成员的分区将主动释放本分区内的所有资源,包括PostgreSQL和VIP。
- 合法的分区中如果没有Master,Pacemaker会提升一个Slave为Master,即发起failover。
- Master上的expgsql会不断监视Slave的复制健康状况,同步复制下会选定一个Slave作为同步Slave。
- 当同步Slave出现故障时,Master上的expgsql会临时将同步复制切换到异步复制,防止Master上的写操作被hang住。如果故障Slave恢复或存在另一个健康的Slave,再切换到同步复制。
- 为防止集群分区后,Slave升级为新Master而旧Master切换到异步复制导致脑裂和数据双写,引入分布式锁服务进行仲裁。Slave升级为新Master和旧Master切换到异步复制前必须先取得锁,避免这两件事同时发生。失去锁的Master会主动停止PostgreSQL进程,防止出现双主。
- 如果分布锁服务发生故障而所有PostgreSQL节点都是健康的,expgsql会忽视锁服务,即不影响集群服务。但在分布锁服务故障期间,Master发生节点故障(注意区分节点故障和资源故障),集群将无法正常failover。
- 同步复制下只有同步Slave才有资格成为候选Master,加上有分布式锁的防护,可以确保failover后数据不丢失。
- 集群初始启动和每次failover时通过
pg_ctl promote提升Slave为Master并使时间线加1,同时记录Master节点名,时间线和切换时的xlog位置到集群CIB。 - 集群重启时根据集群CIB中记录的信息确定Master节点,并保持时间线不变。
- expgsql启动PostgreSQL前会检查该节点的时间线和xlog,如果和集群CIB中记录的信息有冲突,将报错。需要人工通过
cls_repair_by_pg_rewind等手段修复。 - 读写VIP和Master节点绑定,只读VIP和其中一个Slave绑定,应用只需访问VIP,无需关心具体访问哪个节点。
集群操作命令一览
-
cls_start
启动集群 -
cls_stop
停止集群 -
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 -
cls_master
输出当前Master节点名 -
cls_status
显示集群状态 -
cls_cleanup
清除资源状态和fail-count。在某个节点上资源失败次数(fail-count)超过3次Pacemaker将不再分配该资源到此节点,人工修复故障后需要调用cleanup让Pacemkaer重新尝试启动资源。 -
cls_reset_master[master]
设置pgsql_REPL_INFO使指定的节点成为Master;如未指定Master,则清除pgsql_REPL_INFO让Pacemaker重新在所有节点中选出xlog位置最新的节点作为Master。仅用于集群中没有任何节点满足Master条件情况下的紧急修复。 -
cls_repair_by_pg_rewind通过pg_rewind修复当前节点,主要用于旧Master的修复,回退超出时间线分叉点的那部分更新,并和新Master建立复制关系。pg_rewind仅在PostgreSQL 9.5以上版本提供 -
cls_rebuild_slave
通过pg_basebackup在当前节点重建Slave。执行该命令前需要停止当前节点上的PostgreSQL进程并清空旧的数据目录。 -
cls_maintenance
切换集群到维护模式使所有资源脱离Pacemaker的控制。当需要重启Pacemaker和Corosync又不能停止PostgreSQL服务时,可以先调用这个命令,Pacemaker和Corosync重启完成后再调用用cls_unmaintenance恢复为普通模式。 -
cls_unmaintenance
从维护模式恢复到普通模式。 -
cls_maintenance_node<nodename> 使节点进入维护模式。维护模式和unmanage resource相比的区别是会取消monitor,比unmanage更彻底。 -
cls_unmaintenance_node<nodename> 解除节点的维护模式。 -
cls_standby_node<nodename>
释放某节点上所有资源。可用于特定节点的维护,比如升级。 -
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集群环境安装与配置
环境准备
-
所有节点设置时钟同步
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ntpdate time.windows.com && hwclock -w -
所有节点设置独立的主机名(node1,node2)
hostnamectl set-hostname node1 -
设置对所有节点的域名解析(修改/etc/hosts)
-
所有节点间设置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节点执行:
-
创建数据目录
mkdir -p /data/postgresql/data chown -R postgres:postgres /data/postgresql/ chmod 0700 /data/postgresql/data -
初始化db
su - postgres initdb -D /data/postgresql/data/ -
修改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。 -
修改
pg_hba.conflocal all all trust host all all 192.168.41.0/24 md5 host replication all 192.168.41.0/24 md5 -
启动postgres
pg_ctl -D /data/postgresql/data/ start -
创建复制用户
createuser --login --replication replication -P9.5以上版本如需要支持pg_rewind,需加上“-s”选项。
createuser --login --replication replication -P -s
创建备数据库
在node2节点执行:
-
创建数据目录
mkdir -p /data/postgresql/data chown -R postgres:postgres /data/postgresql/ chmod 0700 /data/postgresql/data -
创建基础备份
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
在任意一个节点上执行:
-
下载pha4pgsql
git clone git://github.com/Chenhuajun/pha4pgsql.git -
编辑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做读负载均衡
-
安装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
