昔我往矣

PostgreSQL实战(下):repmgr主从自动切换

2021年03月11日

本系列分为上下2篇,上篇是搭建PostgreSQL主从集群,下篇是使用repmgr配置高可用PostgreSQL集群。推荐先阅读上篇文章了解Postgres主从搭建和手动切换方法之后,再阅读本文。

接上一篇文章,已经搭建好了PostgresSQL服务器,而且已经配置好了主从,现在尝试使用repmgr来管理PostgresSQL的高可用自动切换。

接上一篇文章,现在主从关系如下:

  • standby server: 172.17.0.7
  • primary server: 172.17.0.8

安装和配置repmgr

在主从服务器上同时进行如下操作:

# yum -y install postgresql10-devel flex git make unzip gcc
# git clone  https://github.com/2ndQuadrant/repmgr
# export PG_CONFIG=/usr/pgsql-10/bin/pg_config
# cd repmgr
# ./configure && make isntall

分别在主从上创建配置文件: /data/pgsql_data/repmgr.conf,在172.17.0.7上的文件内容:

node_id=1
node_name='172.17.0.7'
conninfo='host=172.17.0.7 user=replicauser dbname=repmgr connect_timeout=2'
data_directory='/data/pgsql_data/10/data'

172.17.0.8上的 /data/pgsql_data/repmgr.conf 文件内容

node_id=2
node_name='172.17.0.8'
conninfo='host=172.17.0.8 user=replicauser dbname=repmgr connect_timeout=2'
data_directory='/data/pgsql_data/10/data'

在primary机器(172.17.0.8)创建repmgr数据库,并给用于同步的用户(replicauser)授权,使用postgres用户操作。

$ createdb repmgr
$ psql
postgres=# alter user replicauser superuser login;
ALTER ROLE
postgres=# alter database repmgr owner to replicauser;
ALTER DATABASE

接着在primary机器(172.17.0.8)上启动repmgr,并注册为primary,用postgres用户执行:

$ /usr/pgsql-10/bin/repmgr -f /data/pgsql_data/repmgr.conf primary register
INFO: connecting to primary database...
NOTICE: attempting to install extension "repmgr"
NOTICE: "repmgr" extension successfully installed
NOTICE: primary node record (ID: 2) registered
$ /usr/pgsql-10/bin/repmgr cluster show      # 查看集群状态
 ID | Name       | Role    | Status    | Upstream | Location | Prio. | TLI
----+------------+---------+-----------+----------+----------+-------+-----
 2  | 172.17.0.8 | primary | * running |          | default  | 100   | 2

primary机器(172.17.0.8)上的repmgr至此已经就绪,接下来操作standby机器(172.17.0.7)。先删除standby上的数据目录,因为standby上的数据同步要使用repmgr程序进行。

$ rm -rf /data/pgsql_data/10/data/*
$ /usr/pgsql-10/bin/repmgr -h 172.17.0.8 -U replicauser -d repmgr -f /data/pgsql_data/repmgr.conf standby clone --dry-run   # 172.16.49.183是主节点ip,dry-run是测试,不实际执行
$  /usr/pgsql-10/bin/repmgr -h 172.17.0.8 -U replicauser -d repmgr -f /data/pgsql_data//repmgr.conf standby clone  # 执行clone,从master上同步数据
# systemctl restart postgresql-10   # 已root用户重启postgresql服务
$ /usr/pgsql-10/bin/repmgr -f /data/pgsql_data/repmgr.conf standby register  --force  # 注册为standby,force的作用是在重新注册的时候,强制更新upstream id, 否则可能导致自动切换失败
INFO: connecting to local node "172.17.0.7" (ID: 1)
INFO: connecting to primary database
WARNING: --upstream-node-id not supplied, assuming upstream node is primary (node ID 2)
INFO: standby registration complete
NOTICE: standby node "172.17.0.7" (ID: 1) successfully registered

# 再次查看集群
$ /usr/pgsql-10/bin/repmgr cluster show --compact
 ID | Name       | Role    | Status    | Upstream   | Location | Prio. | TLI
----+------------+---------+-----------+------------+----------+-------+-----
 1  | 172.17.0.7 | standby |   running | 172.17.0.8 | default  | 100   | 2
 2  | 172.17.0.8 | primary | * running |            | default  | 100   | 2

配置repmgrd自动切换

在2台机器上修改主配置文件/data/pgsql_data/10/data/postgresql.conf

...
shared_preload_libraries = 'pg_stat_statements,repmgr'
...

然后用root用户重启postgresql

# systemctl restart postgresql-10.service

接下来修改repmgrd的配置文件/data/pgsql_data/repmgr.conf,在repmgr.conf文件中追加如下5行,用来指定故障发生时的切换行为。

……

log_file='/tmp/repmgr.log'
pg_bindir='/usr/pgsql-10/bin/'
failover=automatic   # 开启自动故障切换
promote_command='/usr/pgsql-10/bin/repmgr standby promote -f /data/pgsql_data/repmgr.conf --log-to-file'
follow_command='/usr/pgsql-10/bin/repmgr standby follow -f /data/pgsql_data/repmgr.conf --log-to-file --upstream-node-id=%n'    

在各个节点上使用postgres用户启动repmgrd

$ /usr/pgsql-10/bin/repmgrd -f /data/pgsql_data/repmgr.conf

故障切换测试

在primary服务器(172.17.0.8)上停掉postgresql,模拟primary服务器发生故障。

$  /usr/pgsql-10/bin/pg_ctl -D /data/pgsql_data/10/data/ -m immediate stop
waiting for server to shut down.... done
server stopped

此时,切换到standby服务器(172.17.0.7)上持续观察集群状态,大约一分钟之后,172.17.0.7切换为primary,查看集群状态结果如下:

$ /usr/pgsql-10/bin/repmgr cluster show --compact
 ID | Name       | Role    | Status    | Upstream | Location | Prio. | TLI
----+------------+---------+-----------+----------+----------+-------+-----
 1  | 172.17.0.7 | primary | * running |          | default  | 100   | 3   
 2  | 172.17.0.8 | primary | - failed  | ?        | default  | 100   |     

WARNING: following issues were detected
  - unable to connect to node "172.17.0.8" (ID: 2)

HINT: execute with --verbose option to see connection error messages

此时,172.17.0.7成为新的primary,数据库变为可写。如果此时启动 172.17.0.8 会发生什么呢?

在172.17.0.8执行如下命令启动postgresql。

$ /usr/pgsql-10/bin/pg_ctl -D /data/pgsql_data/10/data/ start

分别到2台机器上查看集群状态:

# 在 172.17.0.7 上看到的集群状态如下
$ repmgr cluster show --compact
 ID | Name       | Role    | Status    | Upstream | Location | Prio. | TLI
----+------------+---------+-----------+----------+----------+-------+-----
 1  | 172.17.0.7 | primary | * running |          | default  | 100   | 3
 2  | 172.17.0.8 | primary | ! running |          | default  | 100   | 2

WARNING: following issues were detected
  - node "172.17.0.8" (ID: 2) is running but the repmgr node record is inactive

# 在 172.17.0.8 上看到的集群状态如下
$ repmgr cluster show --compact
 ID | Name       | Role    | Status               | Upstream | Location | Prio. | TLI
----+------------+---------+----------------------+----------+----------+-------+-----
 1  | 172.17.0.7 | standby | ! running as primary |          | default  | 100   | 3
 2  | 172.17.0.8 | primary | * running            |          | default  | 100   | 2

WARNING: following issues were detected
  - node "172.17.0.7" (ID: 1) is registered as standby but running as primary

发现2台机器现实的集群状态不一样,这就是明显的脑裂现象,需要我们手动干预来修复。修复的操作方法和重新配置新的standby机器一样,把172.17.0.8配置为172.17.0.7的standby,看前面的操作步骤即可,不再做详细演示。

优化故障切换行为

在现在的情况下,如果发生故障,既不会给相关人员发送通知去人工干预恢复主从配置,也不会发生Primary服务器的IP地址切换,此时我们都不知道发生了问题,客户端的请求还是会连接到原来的主服务器而持续报错。

我们可以通过定制脚本来完成这些自动化的功能。一种可行的方法是给主服务器设置一个域名,当发生主从切换的时候,同时把域名也解析到新的primary服务器上。当应用通过域名重连数据库的时候,就可以连接到新的primary机器。

下面是一个待完成的通知和域名切换脚本/data/pgsql_data/promote_postgresql.sh

#!/bin/bash
notification_api="http://api.xnow.me/api/message"
dns_api="http://dnsapi.xnow.me/api/record"   
domain="xnow.me"
record="primary.postgresql"    # 完整的primary域名是 primary.postgresql.xnow.me
server_ip=$1   # 把新的primary ip传递进来

send_notification() {
   curl -X POST -H "content-type:application/json" $notification_api \
                 -d '{"title": "PostgreSQL发生了主从切换", "type": "wechat", "to":["someone"], "content": "'"PostgreSQL: $server_ip promote to be new primary, start switchover domain $record.$domain to $server_ip."'"}'
}

record_id=$(curl "$dns_api?domain=${domain}&record=${record}" | jq .data[0].id)

switchover_dns() {
   curl -X PUT -H "content-type:application/json" $dns_api \
                 -d '{"status": 1, "value": "'"$server_ip"'", "type": "A", "record": "'"$record"'", "line": "default", "domain": "'"$domain"'","record_id": "'"${record_id}"'"}'
}

send_notification
switchover_dns

注意:这个脚本是搭配了我们公司的DNS和通知发送的http api服务使用,如果没有这种的api或者api参数不一样,是肯定无法使用这个脚本的。所以,这个脚本只是用作简单的示范。

可以使用多个方法来完成以上脚本的这些工作,比如使用python编写切换和通知脚本,使用邮件smtp等各种方式来实现通知。但是目标就是实现问题通知和域名切换。

我们接着配置repmgr的配置文件,修改/data/pgsql_data/repmgr.conf,修改promote_command这一行

...
promote_command='/usr/pgsql-10/bin/repmgr standby promote -f /data/pgsql_data/repmgr.conf --log-to-file && bash /data/pgsql_data/promote_postgresql.sh 172.17.0.7'  # 修改这行调用上面的脚本,参数172.17.0.7更换为本机的ip地址
...

保存退出后重启repmgrd服务

$ kill $(cat /tmp/repmgrd.pid)
$ /usr/pgsql-10/bin/repmgrd -f /data/pgsql_data/repmgr.conf

完成上面的工作,就已经是一个可以在生产环境使用的高可用postgresql服务了。但是,postgresql并不是我的工作领域,上面的内容也许有很多错误,还请谨慎使用。

其它方案

除了repmgr这个方案外,还有许多postgresql的高可用方案,比如keepalived的虚ip切换等等。不同方案有自己的优势,在使用中可以广泛比较和参考。

参考:
Repmgr: http://citusdb.cn/?p=1068
PostgreSQL使用repmgr配置级联复制:https://my.oschina.net/u/4360424/blog/3217743
repmgrd basic configuration:https://repmgr.org/docs/4.0/repmgrd-basic-configuration.html

当前暂无评论 »

添加新评论 »