一、pgpool-II简介

pgpool-II的作用,可以以redis的sentinel作参考,都是为了完成主从复制的高可用,实现故障迁移。对于Timescale,或者PostgreSQL数据库来说,基于流复制的故障迁移,有pgpool,pacemaker+corosync等解决方案。这里选择了pgpool,而pgpool-I已经被弃用,所以自然而然的选择了pgpool-II中间件技术。

pgpool-II可以看作一个,介于服务器和客户端之间的中间件,对应数据库服务器来说,它就相当于客户端;对于客户端来说,它就相当于服务器。

二、参考文件

配置流程及配置文件参考:
Postgresql流复制+pgpool实现高可用
PGPool-II+PG流复制实现HA主备切换
完整配置文件参考:pgpool-II 手册
入门教程参考:pgpool-II 入门教程
官方网站:pgpool Wiki

三、注意

该文章,是基于上篇文件的基础上进行配置,已经配置好了Timescale数据库的主从异步流复制,是在此基础上完成进一步的故障迁移的。

上篇文章参考:Docker实现TimescaleDB 基于异步流的主从复制(四)

四、具体步骤

1.运行普通容器

docker run postdock/pgpool:latest

2.将容器内的两个文件夹拷贝出来

docker cp 容器id:/usr/local/etc /data/pgpool
docker cp 容器id:/usr/local/bin/pgpool  /data/pgsh

解释:将对应容器id内部的冒号后的文件内容,拷贝到容器外部,即第二个文件中。比如上例,将容器id内部的/usr/local/bin/pgpool文件夹内容,拷贝到容器外部/data/pgsh文件夹中。所以,容器内部的地址不能随意改变,容器外部的文件地址可根据需求自定义。

注意docker cp 容器外部地址 容器id:容器内部地址,即将两个地址反过来,是将容器外部的文件拷贝到容器内部。

3.修改初始化脚本

(1)修改pgpool_setup.sh脚本文件

A.pgpool_setup.sh文件的cp -f /var/pgpool_configs/pgpool.conf $CONFIG_FILE前用#注释,一般情况下,位于配置文件的第三行,即:

# cp -f /var/pgpool_configs/pgpool.conf $CONFIG_FILE

原因:该版本docker容器重启时,会初始化配置文件,该行的作用就是初始化配置文件,将该行注释,即重启docker容器时,不会改变配置文件。
B. 再将该文件以下这行注释,位于pgpool_setup.sh文件的第五行

# echo "host all all 0.0.0.0/0 md5" > $HBA_FILE

原因:该行的作用,是每次重启docker容器时,默认将host all all 0.0.0.0/0 md5语句输入到pool_hba.conf文件中,导致无法修改该文件(即每次修改该文件后,重启docker容器,该文件又会回复到默认状态)。

(2)修改entrypoint.sh脚本文件

entrypoint.sh 文件的最后一句后面添加:

gosu postgres /usr/local/bin/pgpool/pgpool_start.sh >> /usr/local/etc/pgpool.log

原因:将配置文件输出到/usr/local/etc/pgpool.log文件中,但目前不知什么原因,文件可以被创建出来,但内里无日志。

4.修改配置文件

(1)修改pool_passwd

打开配置文件,其中应该会有之前在PostgreSQL中,配置的postgres账号,以及其密码123456的md5格式,即:

postgres:md5a3556571e93b0d20722ba62be61e8c2d

所以不用修改该文件。如果没有,可去对应数据库用select usename,passwd from pg_shadow;语句查询。
同时,该配置文件会自动添加一行数据:

replication_user:md587cb5f1bfe7a883399a0b24a741e252c

这也是我们在上一篇中,配置该用户的原因。如果不在上篇文章中配置,在此时配置应该也是可以的(未测试)。
上篇文章参考:Docker实现TimescaleDB 基于异步流的主从复制(四),其中主机配置的第6小节:配置pgpool用户。

(2)配置pgpool.conf文件
listen_addresses = '*'

port = 9999

pcp_socket_dir = '/tmp'

# 配置主节点
backend_hostname0 = '192.168.50.34' #主机ip
backend_port0 = 5432
backend_weight0 = 1 #loadbalance不开启,无效
backend_data_directory0 = '/var/lib/postgresql/9.5/main'
backend_flag0 = 'ALLOW_TO_FAILOVER'

# 配置从节点
backend_hostname1 = '192.168.50.31'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/data1'
backend_flag1 = 'ALLOW_TO_FAILOVER'

#配置其他
enable_pool_hba = on
pool_passwd = 'pool_passwd'

replication_mode = off
load_balance_mode = on
master_slave_mode = on
master_slave_sub_mode = 'stream'

sr_check_period = 5
sr_check_user = 'repuser' #流复制账号,第四篇配置的超级账号
sr_check_password = '123456'
sr_check_database = 'postgres'

# 修改pid地址,该地址需要与容器内部地址一致,不一定与下面地址相同
pid_file_name = '/var/run/postgresql/pgpool.pid'

# 添加故障迁移脚本
failover_command = '/usr/local/etc/failover.sh %d %P %H %R'

#健康检查(自动检查主机宕机,然后执行故障迁移脚本)
health_check_period = 10
health_check_timeout = 10
health_check_user = 'postgres'
health_check_password = '123456'
health_check_database = 'postgres'
health_check_max_retries = 0
health_check_retry_delay = 1
connect_timeout = 10000

# 添加日志配置(根据自己的情况配置)
log_destination = 'stderr'
client_min_messages = debug5 
log_min_messages = debug5
(3)配置pool_hba.conf文件
host replication  repuser  0.0.0.0/0 trust
host all all 0.0.0.0/0 md5

该文件会有默认配置:host all all 0.0.0.0/0 md5。仅在该文件添加一行:host replication repuser 0.0.0.0/0 trust。添加的该行配置是在pg_hba.conf文件中IPv6底下的一行。

(4)配置pcp.conf文件

在该文件中添加:

pgpool:5f4dcc3b5aa765d61d8327deb882cf99

作用:该配置文件的作用,是在pgpool容器中,运行pcp相关命令时(特指pcp_attach_node命令),提供账号、密码的输入功能。

md55f4dcc3b5aa765d61d8327deb882cf99password这几个字母的md5格式。

:该数据,是通过在pgpool-II容器中,运行/usr/sbin/pg_md5 password命令而得。经测试,所有该容器的运行结果都是该值,所以直接将之上数据,添加到该文件即可。

(5)创建failover.sh脚本文件,修改权限777

该文件位于/data/pgpool文件夹下。

#!/bin/bash
falling_node=$1
old_primary=$2
new_primary=$3
pgdata=$4
currTime=$(date +"%Y-%m-%d %T")
pghome=/opt/pgsql
log=/tmp/failocer.log
date >> $log

echo $currTime
echo "falling_node =$falling_node "
echo "old_primary=$old primary"
echo "new_primary=$new_primary "
echo "pgdata=$pgdata "

ssh -T root@new_primary /data/pgpool/a.sh
exit 0 ; 

该脚本会由健康检测机制,自动检测宕掉的机器,然后执行该脚本文件。
日志会打印在/data/pgpool/pgpool.log文件中。

(6)创建a.sh脚本文件,修改权限777

该脚本文件位于/data/pgpool文件夹下。

#!/bin/bash

docker exec -i 51b4cc62ad49 su postgres -c "/usr/local/bin/pg_ctl promote"

注意-i,没有t。
如果为-it,会报错:报错:the input device is not a TTY

5.run一个新的容器,将文件挂载进去

    docker run -p 9999:9999 -v /data/pgpool:/usr/local/etc -v /data/pgsh:/usr/local/bin/pgpool  postdock/pgpool:latest 
             

6.设置 ssh免密登录

设置pgpool容器与容器外部主机和备机的免密登录。
参考文档:Linux远程登录免密码设置

(1)在pgpool容器中下载openssh

因为该容器存在问题,yum以及apt-get无法使用,不能使用apt-get install openssh-server直接下载openssh,所以使用压缩包安装openssh。
下载网址:mirror.sfo12.us.leaseweb.net,我下载的7.4版本,即openssh-7.4p1.tar.gz
使用ftp上传至linux系统的/opt文件,将该文件拷贝进容器中:(习惯性的将第三方软件放在/opt文件中)

docker cp /opt/openssh-7.4p1.tar.gz  容器id:/opt

解压缩:
进入/opt文件夹中,运行以下命令:

tar -zxvf openssh-7.4p1.tar.gz

如此,就可以使用ssh相关命令了。

(2)在pgpool容器内部生成密钥对
ssh-keygen

连续回车,最后会生成随机RSA 2048图,即表示成功。
在这里插入图片描述
同时,会在容器的/root/.ssh隐藏文件夹中,生成公钥文件id_rsa.pub,如下所示:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCt/cBpRoTKyIA2QlEkcQur2rR8wKhAqhKZ8PluIly/KcX1oo/fvRAE+NhvHjY+y/NrSkWo145ks9/tPnDR/MaGYhveE9FGgBXrQg8gvFpPmtvHxnb2s2fsg176QLB9FnjGMZk2bSvfl8yje07xfuNVZCNOrbspoYVO+F49ijfzALayktDEyxbkwztHjOLoKkB0yZRP5hH1d2yhFTOtmMZ+5ZJh6Glq5mHX7foFFy0JjLaUtqO/Xyf82JAUAYnLNIF33513DUSkWepKOZo3CvpmKMl4ZDouVkOl4h0VzgIhA2zr6f2ODbKUDSprJoP/7D0WV4jX7ttDJG/PSb+tG+bz root@398823f95a99

验证该公钥是否正确,拉取到最后,看是否为root@容器id

(3)将容器内部的文件拷贝至容器外部

将第(2)步,容器内部生成的公钥id_rsa.pub,拷贝至主机和备机的authorized_keys文件夹中。id_rsa.pub文件位于~/.ssh,即/root/.ssh隐藏文件夹中,authorized_keys文件夹同样位于/root/.ssh隐藏文件夹中。

拷贝文件,容器外部运行命令:

docker cp pgpool容器id:/root/.ssh/id_rsa.pub  /root/.ssh/authorized_keys

这是将本机的pgpool容器与本机完成了免密登录,如果要进行本机的pgpool容器与外机完成免密登录,同样需要将此文件,拷贝至外机的该目录下。但由于该文件位于隐藏文件夹下,不能直接使用ftp软件完成下载和上传。所以需要将该文件从隐藏文件夹下,拷贝出来,借助中转拷贝。

将本机的id_rsa.pub文件从隐藏文件中拷贝出来(随便一个地址):

cp /root/.ssh/id_rsa.pub /root

使用ftp软件,将该文件下载到本地,再上传至外机。
在外机进行操作,将此文件拷贝至authorized_keys文件中:

cp /pub文件地址/id_rsa.pub /root/.ssh/authorized_keys
(4)使用免密登录

在pgpool容器内部,使用命令:

ssh root@外部ip

即可免密码登入主机备机,使用exit登出。
如果有免密登录容器内部的需求:

ssh root@容器id

7.测试:

(1)初始正常节点

进入timescale容器内部(主从皆可),
运行su postgres命令,切换到postgres 用户,
运行psql -h192.168.50.34 -p9999 -Upostgres命令,输入密码123456
运行show pool_nodes;命令,显示:
在这里插入图片描述可见,主机为34,备机为31.

(2)故障迁移–宕掉主机,备机提升为primary

目前因脚本未完全配置,故障迁移需手动迁移,情况如下:
宕掉主机34的timescale容器,进入pgpool容器,免密登录至31备机,
运行docker exec -it 51b4cc62ad49 su postgres -c "/usr/local/bin/pg_ctl promote"命令,
报错:pg_ctl: cannot promote server; server is not in standby mode
[所以不需要运行该命令]
进入容器内部,连接pgpool:
在这里插入图片描述

经测试:不通过容器内ssh登录,直接去外机运行相应命令,也可进行主备切换。
查看节点
在这里插入图片描述可见,31被提升为了主机。
启动34的timescale容器,重新连接,查看节点,34状态为down,存在问题。

(3)故障恢复–将宕掉的主机重新以stanbdy的身份加入到pgpool

目前脚本有问题,需在容器外手动执行a.sh脚本文件中的内容。
修改.done.conf
启动34节点的timescale容器,
进入pgpool容器中,执行:

 pcp_attach_node -d -U pgpool -p9898 -n 0

输入密码:password
查看节点:
在这里插入图片描述
目前存在的问题:虽然显示的为34复制主机,但是用navicat软件添加数据,复制不成功。




以下为之前恢复所做笔记(不用看):




A. 修改配置文件pgpool_conf,将host0改为现在的primary–31,将host1改为现在的standby–34,重启pgpool容器。

注意:经测试,仅改变配置文件,就可以进行故障恢复。不过存在,手动恢复比较繁琐的问题。

B. 进入pgpool容器,运行命令,将节点34添加到pgpool中:

B1 参考博客的写法:

/usr/sbin/pcp_attach_node 10 localhost 9898 pgpool cloud 0

B2 pcp_attach_node --help结果:

root@33058e47e47d:/# /usr/sbin/pcp_attach_node --help

pcp_attach_node - attach a node from pgpool-II
Usage:
pcp_attach_node [OPTION...] [node-id]
Options:
  -U, --username=NAME    username for PCP authentication
  -h, --host=HOSTNAME    pgpool-II host
  -p, --port=PORT        PCP port number
  -w, --no-password      never prompt for password
  -W, --password         force password prompt (should happen automatically)
  -n, --node-id=NODEID   ID of a backend node
  -d, --debug            enable debug message (optional)
  -v, --verbose          output verbose messages
  -?, --help             print this help

B3.我的写法
B3.0 根据 A 修改配置文件,改变节点。(改变配置文件,为手动恢复;)
B3.1 修改pgpool.conf配置文件:

pcp_socket_dir = '/tmp'

不然会报错:

ERROR: connection to socket "/tmp/.s.PGSQL.9898" failed with error "No such file or directory"

B3.2 进入pgpool容器,运行以下命令:

/usr/sbin/pcp_attach_node 10 localhost 9898 pgpool postgres 0 -v -d

输入密码:123456
报错

FATAL:  authentication failed for user "root"
DETAIL:  username and/or password does not match

B3.3 进入timescale容器,查看节点:
在这里插入图片描述
可见:34由down提升为up,节点从0变为1,正式成为备机。

疑惑

a.我对该添加节点命令的疑惑与理解

10不知道什么意思,
localhost是pgpool所在主机ip,
9898是默认端口,
pgpool不知道是什么名,应该是默认?,
postgres猜测是在pool_passwd配置文件中配置的账号,
0是使用show nodes;查询到的34节点。

8.错误:

(1)连接错误

问题日志
如果测试时,产生错误(主要产生于第一次配置好pgpool,用timescale连接pgpool,查看节点的时候):

DETAIL: message length (12) in slot 1 does not match with slot 0(8)

那么,就是timescale的pg_hba.conf文件的问题,

解决方案
修改timescale的pg_hba.conf文件,全部注释,添加:

host all all 0.0.0.0/0 md5

参考博客(虽然也没啥卵用,仅供参考):
登录 pgpool 的 9999 提示 DETAIL: message length (12) in slot 1 does not match with slot 0(8)

(2)pgpool容器重启不了

查看问题:使用docker logs docker容器id查看容器日志。
错误信息

2019-12-16 01:04:17: pid 23: FATAL:  failed to bind a socket: "/tmp/.s.PGSQL.9898"
2019-12-16 01:04:17: pid 23: DETAIL:  bind socket failed with error: "Address already in use"

这是由于容器没有正常关闭,tmp缓存文件未清除,所以导致地址信息被占用。
参考文档:pgpool-ii 安装手册 基于Centos7.3

解决方案
entrypoint.sh文件中,添加/修改:

rm -f /tmp/.s.PGSQL*

总结
引起该问题的原因,是因为我们在pgpool.conf配置文件中,修改pcp_socket_dir = '/tmp'而导致的。
但是该信息必须修改,不然会报另一个错误==>(3) 故障恢复—>无/tmp/.s.PGSQL.9898文件错误。

(3)故障恢复——>无/tmp/.s.PGSQL.9898文件错误。

错误日志

ERROR: connection to socket "/tmp/.s.PGSQL.9898" failed with error "No such file or directory"

解决方案
修改pgpool.conf配置文件:

pcp_socket_dir = '/tmp'

备机pghba

local   all             all                                     md5

host    replication     repuser           0.0.0.0/0         trust

host all all all md5
host all all 0.0.0.0/0 md5

备机poolhba

host    replication     repuser           0.0.0.0/0         trust
host all all 0.0.0.0/0 md5

主机pghba

local   all             all                                     md5

host    replication     repuser           0.0.0.0/0         trust

host all all all md5
host all all 0.0.0.0/0 md5
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐