1,组件介绍:
1.1 patroni:
Patroni是一个模板,您可以使用Python创建自己的定制化、高可用性解决方案,并为最大的可访问性提供分布式配置存储,如ZooKeeper、etcd、Consul或Kubernetes。Patroni 起源于Compose项目Governor的一个分支,包括许多新功能。patroni在数据中心或其他任何地方快速部署 HA PostgreSQL中成为非常有用的工具。
1.2 consul
consul就是提供服务发现的工具。consul是分布式的、高可用、横向扩展的。consul提供的一些关键特性:
service discovery: consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
health checking: 健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
key/value storage: 一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
multi-datacenter(多数据中心):无需复杂的配置,即可支持任意数量的区域。
上图来自于consul官方文档
我们只看数据中心1,可以看出consul的集群是由N个SERVER,加上M个CLIENT组成的。而不管是SERVER还是CLIENT,都是consul的一个节点,所有的服务都可以注册到这些节点上,正是通过这些节点实现服务注册信息的共享。
CLIENT
CLIENT表示consul的client模式,就是客户端模式。是consul节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到SERVER,本身是不持久化这些信息。
SERVER
SERVER表示consul的server模式,表明这个consul是个server,这种模式下,功能和CLIENT都一样,唯一不同的是,它会把所有的信息持久化的本地,这样遇到故障,信息是可以被保留的。
SERVER-LEADER
中间那个SERVER下面有LEADER的字眼,表明这个SERVER是它们的老大,它和其它SERVER不一样的一点是,它需要负责同步注册的信息给其它的SERVER,同时也要负责各个节点的健康监测。
其它信息其它信息包括它们之间的通信方式,还有一些协议信息,算法。它们是用于保证节点之间的数据同步,实时性要求等等一系列集群问题的解决。可以参考官方文档。
1.3 consul-template
consul-template 是 Consul 的一个守护程序,使用 consul-template 可以方便快速的实现对 Consul Key/Value 存储系统的访问,可以从 KV 系统中读取数据、监视变动、同步本地文件;
consul-template 的特点
智能发现: 一旦开始运行 consul-template ,consul-template 将会自动的发现 Consul 中的 Key/Value 变更,并自动更新到本地模板文件。(—这个特点是我们在这个架构中使用的最显著的一个特点)。
重复过滤: consul-template 内部可以跨实例对数据进行重复筛选,多个 consul-template 实例进行选举,确定只有一个 consul-template 执行 KV 查询,然后将结果同步到其它 consul-template 实例,在命令行中使用 -dedup 标记或者在配置文件中配置“deduplicate” 来启用重复过滤功能。
快速使用: 支持命令行和配置文件,有多种方法可以运行Consul Template,但最常见的模式是将Consul Template作为系统服务运行。
Dry Mode: 在Dry模式,Consul-Template会将结果呈现在STDOUT,操作员可以检查输出是否正常,以决定更换模板是否安全
1.4 pgbouncer
pgbouncer 是 PostgreSQL 的轻量的连接池,支持三种模式。
Session pooling/会话连接池
最礼貌的方法。在客户端连接的时候,在它的连接生命期内,会给它赋予一个服务器连接。在客户端断开的时候,服务器连接会放回到连接池中。
Transaction pooling/事务连接池
服务器连接只有在一个事务里的时候才赋予客户端。在 PgBouncer 注意到事务结束的时候,服务器将会放回连接池中。这是一个 hack,因为它打破了应用对后段连接的看法。只有在应用配合这样的使用模式,没有使用会破坏这种使用模式的时候才能用这个连接方式。参阅下标获取会破坏 这种模式的特性。
Statement pooling/语句连接池
最激进的模式。这是事务连接池的一个扭曲的变种 - 不允许多语句的事务。这就意味着是在客户端强制“autocomit”模式,主要是给 PL/Proxy 用的。
1.5 keepalived
1—是什么
keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障。
2—原理
keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。
keepalived主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式。vrrp模块是来实现VRRP协议的。
2,部署配置安装
2.0 高可用部署架构图:
使用感受:部署部件较多,较为麻烦,但是使用便捷
2.1 环境介绍:
Ubuntu Server 20.04 LTS 64位
机器:
192.168.2.10(主)
192.168.2.12
192.168.2.2
pg版本:12.10
设置hostname:
hostname pg1/2/3
/etc/hostname 里面设置为pg1\pg2\pg3
然后在每个/etc/hosts里面加入:
192.168.2.10 pg1
192.168.2.2 pg2
192.168.2.12 pg3
搭建postgresql主从集群,2.10为主,过程略
(注意点:需要在pg_hba.conf文件中加入从库的replication权限和访问postgres数据库的权限:
host all all 192.168.2.1/24 md5 host replication all 192.168.2.1/24 md5
复制
)
2.2 consul下载安装
cd /usr/local/src wget https://releases.hashicorp.com/consul/1.11.5/consul_1.11.5_linux_amd64.zip cp consul /usr/sbin/ consul -v ##查看版本信息
复制
2.3 创建目录
mkdir /etc/consul.d mkdir /data/consul mkdir /data/consul_log mkdir -p /data/patroni/log chown postgres:postgres /data/ -R
复制
2.4 逐个节点 切换postgres用户 启动consul
nohup consul agent -server -bootstrap-expect=3 -data-dir=/data/consul -node=192.168.2.10 -bind=192.168.2.10 -enable-script-checks=true -config-dir=/etc/consul.d -rejoin -ui -log-file=/data/consul_log/ -client=0.0.0.0 & nohup consul agent -server -bootstrap-expect=3 -data-dir=/data/consul -node=192.168.2.12 -bind=192.168.2.12 -enable-script-checks=true -config-dir=/etc/consul.d -rejoin -ui -log-file=/data/consul_log/ -client=0.0.0.0 & nohup consul agent -server -bootstrap-expect=3 -data-dir=/data/consul -node=192.168.2.2 -bind=192.168.2.2 -enable-script-checks=true -config-dir=/etc/consul.d -rejoin -ui -log-file=/data/consul_log/ -client=0.0.0.0 &
复制
2.5 其他节点 切换postgres用户 加入主节点 :
consul join 192.168.2.10 Successfully joined cluster by contacting 1 nodes.
复制
2.6 查看集群成员:
consul members Node Address Status Type Build Protocol DC Partition Segment 192.168.2.10 192.168.2.10:8301 alive server 1.11.5 2 dc1 default <all> 192.168.2.12 192.168.2.12:8301 alive server 1.11.5 2 dc1 default <all> 192.168.2.2 192.168.2.2:8301 alive server 1.11.5 2 dc1 default <all>
复制
2.7 安装配置patroni:
(如果是centos 7之类的系统需要安装python 3)
cd /usr/local/src wget https://github.com/zalando/patroni/archive/refs/heads/master.zip unzip master.zip cd /usr/local/src/patroni-master apt-get install python3-psycopg2 pip install patroni[consul]
复制
2.8 配置patroni
将模板cp过来:
cp /usr/local/src/patroni-master/postgres2.yml /data/patroni/patroni-config.yml su - postgres echo ‘192.168.2.2:5432:*:replica:qwe123’> /home/postgres/.pgpass chmod 0600 /home/postgres/.pgpass
复制
主库配置更改/data/patroni/patroni-config.yml
(备注:wal_keep_segments: 500 在pg<=V12中 ; wal_keep_size:8GB 在pg>V13中)设置:
scope: pgtestha
namespace: /data/patroni/service/
name: pg2
log:
level: INFO
traceback_level: ERROR
dir: /data/patroni/log/
file_num: 10
file_size: 104857600
restapi:
listen: 192.168.2.10:8010
connect_address: 192.168.2.10:8010
consul:
host: 192.168.2.10:8500
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
wal_level: replica
hot_standby: “on”
max_connections: 3000
max_worker_processes: 2
wal_keep_segments: 500
max_wal_senders: 10
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: “on”
track_commit_timestamp: “off”
archive_mode: “on”
listen_addresses: “*”
port: 5432
log_directory: “on”
log_statement: “mod”
log_directory: “/data/pg_log”
log_destination: “csvlog”
log_filename: “pg-%d.log”
log_rotation_size: “500MB”
archive_command: mkdir -p /data/pg_archive/ && test ! -f /data/pg_archive/%f && cp %p /data/pg_archive/%f
recovery_conf:
restore_command: cp /data/pg_archive/%f %p
######Some additional users users which needs to be created after initializing new cluster
users:
admin:
password: admin%
options:
- createrole
- createdb
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.2.10:5432
data_dir: /data/pg_data
pgpass: /home/postgres/.pgpass
bin_dir: /usr/local/pgsql/bin/
config_dir: /data/pg_data
####### pgpass: /tmp/pgpass2
authentication:
replication:
username: replica
password: qwe123
superuser:
username: postgres
password: qwe123
rewind: # Has no effect on postgres 10 and lower
username: postgres
password: qwe123
parameters:
unix_socket_directories: ‘/tmp’
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
复制
从库192.168.2.2 :
scope: pgtestha
namespace: /data/patroni/service/
name: pg2
log:
level: INFO
traceback_level: ERROR
dir: /data/patroni/log/
file_num: 10
file_size: 104857600
restapi:
listen: 192.168.2.2:8010
connect_address: 192.168.2.2:8010
consul:
host: 192.168.2.10:8500
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
wal_level: replica
hot_standby: “on”
max_connections: 3000
max_worker_processes: 2
wal_keep_segments: 500
max_wal_senders: 10
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: “on”
track_commit_timestamp: “off”
archive_mode: “on”
listen_addresses: “*”
port: 5432
log_directory: “on”
log_statement: “mod”
log_directory: “/data/pg_log”
log_destination: “csvlog”
log_filename: “pg-%d.log”
log_rotation_size: “500MB”
archive_command: mkdir -p /data/pg_archive/ && test ! -f /data/pg_archive/%f && cp %p /data/pg_archive/%f
recovery_conf:
restore_command: cp /data/pg_archive/%f %p
######Some additional users users which needs to be created after initializing new cluster
users:
admin:
password: admin%
options:
- createrole
- createdb
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.2.2:5432
data_dir: /data/pg_data
pgpass: /home/postgres/.pgpass
bin_dir: /usr/local/pgsql/bin/
config_dir: /data/pg_data
####### pgpass: /tmp/pgpass2
authentication:
replication:
username: replica
password: qwe123
superuser:
username: postgres
password: qwe123
rewind: # Has no effect on postgres 10 and lower
username: postgres
password: qwe123
parameters:
unix_socket_directories: ‘/tmp’
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
复制
从库192.168.2.12 配置文件设置:
scope: pgtestha
namespace: /data/patroni/service/
name: pg2
log:
level: INFO
traceback_level: ERROR
dir: /data/patroni/log/
file_num: 10
file_size: 104857600
restapi:
listen: 192.168.2.12:8010
connect_address: 192.168.2.12:8010
consul:
host: 192.168.2.10:8500
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
wal_level: replica
hot_standby: “on”
max_connections: 3000
max_worker_processes: 2
wal_keep_segments: 500
max_wal_senders: 10
max_replication_slots: 10
max_prepared_transactions: 0
max_locks_per_transaction: 64
wal_log_hints: “on”
track_commit_timestamp: “off”
archive_mode: “on”
listen_addresses: “*”
port: 5432
log_directory: “on”
log_statement: “mod”
log_directory: “/data/pg_log”
log_destination: “csvlog”
log_filename: “pg-%d.log”
log_rotation_size: “500MB”
archive_command: mkdir -p /data/pg_archive/ && test ! -f /data/pg_archive/%f && cp %p /data/pg_archive/%f
recovery_conf:
restore_command: cp /data/pg_archive/%f %p
######Some additional users users which needs to be created after initializing new cluster
users:
admin:
password: admin%
options:
- createrole
- createdb
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.2.12:5432
data_dir: /data/pg_data
pgpass: /home/postgres/.pgpass
bin_dir: /usr/local/pgsql/bin/
config_dir: /data/pg_data
####### pgpass: /tmp/pgpass2
authentication:
replication:
username: replica
password: qwe123
superuser:
username: postgres
password: qwe123
rewind: # Has no effect on postgres 10 and lower
username: postgres
password: qwe123
parameters:
unix_socket_directories: ‘/tmp’
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
复制
2.9 修改目录权限
chown -R postgres:postgres /data/
复制
2.10 切换postgres用户启动patroni:
nohup patroni /data/patroni/patroni-config.yml &
###查看patroni 下集群状态
patronictl -c /data/patroni/patroni-config.yml list
复制
在主库2.10中查看主从情况:
查看相关配置:
patronictl -c /data/patroni/patroni-config.yml show-config patronictl -c /data/patroni/patroni-config.yml edit-config
复制
编辑配置文件的操作是在GUN nano界面操作,只能更新现的配置参数,可以新增无需重启的参数,不能新增需要重启的参数,并且通过该方式的参数会落地文件到数据库的配置文件postgresql.conf中。编辑完成之后ctrl+x保存,再输入y
然后再ctrl+T保存到对应的文件(上图中间上面位置是文件名)
2.11 root下载安装pgbouncer:
cd /usr/local/src
apt-get install libevent*
wget https://github.com/openssl/openssl/archive/refs/heads/master.zip
unzip master.zip
cd openssl-master/
./config
make &&make install
wget https://www.pgbouncer.org/downloads/files/1.17.0/pgbouncer-1.17.0.tar.gz
tar -zxvf pgbouncer-1.17.0.tar.gz
cd pgbouncer-1.17.0/
./configure —prefix=/usr/local/
make && make install
######查看安装情况:
pgbouncer -V
#####如果有报错:
root@pgtest3:/usr/local/src/pgbouncer-1.17.0# pgbouncer -V
pgbouncer: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory
####需要:
ln -s /usr/local/lib64/libssl.so.3 /usr/local/lib/libssl.so.3
ln -s /usr/local/lib64/libcrypto.so.3 /usr/local/lib/libcrypto.so.3
ldconfig
复制
####最后检查安装情况,以及pgbouncer的版本信息:
2.12 切换到postgres用户下面
mkdir /data/pgbouncer/{log,etc,run} -p cp /usr/local/src/pgbouncer-1.17.0/etc/pgbouncer.ini /data/pgbouncer/etc/ vim /data/pgbouncer/etc/pgbouncer.ini #更改相关配置 [databases] postgres= host=192.168.2.12 port=5432 dbname=postgres [users] [pgbouncer] logfile = /data/pgbouncer/log/pgbouncer.log pidfile = /data/pgbouncer/run/pgbouncer.pid listen_addr = * listen_port = 6432 auth_type = md5 auth_file = /data/pgbouncer/etc/userlist.txt admin_users = pgbuser #需要在auth_file 里面体现 stats_users = pgbuser #需要在auth_file 里面体现 max_client_conn = 3000 default_pool_size = 1000
复制
其中auth_file的内容会根据auth_type一起起作用:
auth_type和auth_file
这两个是pgbouncer用以完成客户端身份认证参数。auth_file中保存用户名和密码,根据验证方式(auth_type)的不同,auth_file的内容也有不同。
md5: 基于md5的密码验证,auth_file中需要有普通文本和md5值两种形式的密码;
crypt: 基于crypt的密码验证(man 3 crypt), auth_file必须包含文本密码;
plain: 明文验证方式;
trust: 不进行验证,但auth_file依然需要保存用户名;
any: 也不进行验证,而且auth_file中不需要保存用户名了。但此种方式需要在pg_template1中明确说明用户名进行真实数据库的登录。如: pg_template1 = host=127.0.0.1 user=exampleuser dbname=template1.否则会报错的。
需要说明的是:auth_file中的用户名、密码都必须使用双引号,否则还是报错。
例如:auth_type = md5,那么user.txt,需要同时包括明文和加密码后的账号密码:
“postgres” “123456” “postgres” “md5a3556571e93b0d20722ba62be61e8c2d”
复制
这里第二行的账号和MD5密码,md5密码为”md5” + md5(password + username)
或者通过查询数据库中pg_authid获取
在数据库服务器上运行,生成的文件userlist.txt放至配置目录下。
还有一个需要重要提醒的是我们的auth_file文件中的username和password必须要用双引号括起来,否则会出问题
启动pgbouncer:
pgbouncer -d /data/pgbouncer/etc/pgbouncer.ini
复制
2.13 下载使用consul-template:
mkdir /usr/local/src/consul-template
cd /usr/local/src/consul-template
wget https://releases.hashicorp.com/consul-template/0.29.0/consul-template_0.29.0_linux_amd64.zip
cp consul-template /usr/sbin/

创建/etc/systemd/system/pgbouncer.service文件,通过systemctl管理pgbouncer服务
root@pg3:~# cat /etc/systemd/system/pgbouncer.service
[Unit]
Description=pgBouncer connection pooling for PostgreSQL
After=syslog.target network.target
[Service]
Type=forking
User=postgres
Group=postgres
PermissionsStartOnly=true
ExecStartPre=-/bin/mkdir -p /data/pgbouncer/{log,etc,run}
ExecStartPre=/bin/chown -R postgres:postgres /data/pgbouncer/
ExecStart=/usr/local/bin/pgbouncer -d /data/pgbouncer/etc/pgbouncer.ini
ExecReload=/bin/kill -SIGHUP $MAINPID
PIDFile=/data/pgbouncer/run/pgbouncer.pid
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
使用root启动consul-template服务:
root@pg3:~# consul-template -config=/data/consul-template/consul-template.config &

## 附 2.14 keepalived 安装
[root@localhost ~]# yum install gcc openssl openssl‐devel libnl libnl‐devel ipvsadm -y
[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# tar -zxf keepalived-2.2.4.tar.gz
[root@localhost src]# cd keepalived-2.2.4
[root@localhost keepalived-2.2.4] ./configure —prefix=/usr/local/keepalived
[root@localhost keepalived-2.2.4] make && make install
[root@localhost keepalived]# cd /usr/local/keepalived
[root@localhost keepalived]#
ln -s /usr/local/src/keepalived-2.2.4/keepalived/etc/init.d/keepalived /etc/init.d/
[root@localhost keepalived]# ln -s /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
[root@localhost keepalived]# ln -s /usr/local/keepalived/sbin/keepalived /usr/local/sbin/
[root@localhost keepalived]# mkdir /etc/keepalived/
[root@localhost keepalived]# ln -s /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
[root@localhost ~]# cat /etc/keepalived/keepalived.conf
[root@localhost keepalived-2.2.4]# systemctl start keepalived
[root@localhost keepalived-2.2.4]# systemctl status keepalived
keepalived 配置
[root@localhost ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
#####邮件通知信息
notification_email {
######### 定义收件人
394106346@qq.com
}
######### 定义发件人
notification_email_from Alexandre.Cassen@firewall.loc
########### SMTP服务器地址
smtp_server 192.168.254.128
smtp_connect_timeout 30
########### 路由器标识,一般不用改,也可以写成每个主机自己的主机名
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
########### 定义用于实例执行的脚本内容,比如可以在线降低优先级,用于强制切换
vrrp_script check_alived {
script “/data/scripts/check_monitor.sh”
interval 10
fall 3
}
########### 一个vrrp_instance就是定义一个虚拟路由器的,实例名称
vrrp_instance VI_1 {
####### 定义初始状态,可以是MASTER或者BACKUP
state MASTER
#######非抢占模式
nopreempt
####### 工作接口,通告选举使用哪个接口进行
interface ens33
####### 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个,而且这个虚拟
####### ID还是虚拟MAC最后一段地址的信息,取值范围0-255
virtual_router_id 51
#权重 如果你上面定义了MASTER,这里的优先级就需要定义的比其他的高
priority 100
#######通告频率 单位s
advert_int 1
####### 通信认证机制,这里是明文认证还有一种是加密认证
authentication {
auth_type PASS
auth_pass 1111
}
####### 设置虚拟VIP地址
virtual_ipaddress {
192.168.254.11
}
####### 追踪脚本,通常用于去执行上面的vrrp_script定义的脚本内容
track_script {
check_alived
}
########### 如果主机状态变成Master|Backup|Fault之后会去执行的通知脚本,脚本要自己写
notify_master "/data/scripts/failover.sh"
notify_fault "/data/scripts/fault.sh"
}
复制
其中脚本:
/data/scripts/check_monitor.sh
:需要监控consul、pgbouncer、consul-template服务是不是正常,如果正常那么脚本就“exit 0” ,否则就“exit 1”
3 高可用以及连接池测试:
将原来的主库停止,并且将data目录进行mv,leader自动漂移到pg2;我们再去pgbouncer的服务器查看相关配置是否已经更新:
我们看到再[databases] 下面的数据库指定host已经变为pg2,连接池切换也正常
测试完成。高可用自动切换,连接池,自动切换
评论
