postgre高可用---主从配置及主从切换 有更新!

  , ,
评论 • 89 浏览

更新说明:改了一些错别字。。

上次写完postgre高可用方案之后,一直想写篇我们在实际项目中的应用。但是一直都没时间(我根本就是忘了,捂脸。。。)。今天晚上要等火车,现在待在公司没什么事情,于是便将篇文档给补出来。
这篇文章将会简单介绍postgre的主从复制操作,以及主库宕机,从库切换的一些实现。

准备

下载postgre,建议去官方下载编译后的run文件。
找到linux版本。
不建议自己下载二进制包,还要编译等,如果内网服务器,需要一堆依赖,很麻烦。
下载完成后直接运行。

 ./postgresql-10.7-1-linux-x64.run

安装步骤略过,默认即可。

主库配置

1.首先建立流复制用户。
CREATE  ROLE foo LOGIN replication ENCRYPTED PASSWORD  '12345';

这个foo用户是后面从库用来监听主库的用户。

2.配置pg_hba.conf文件。

在replication privilege下面增加配置。
如:

host    replication     all             192.168.0.6/32          md5

这个ip是从库的ip。

单主从的话,主库配置到这里就可以了。

如果需要主库宕机后,从库提升为主库,且主库再次启动降级为从库还需要如下配置。

3.主从切换配置。

建议将postgresql.conf里面的


#最大发送者

max_wal_senders = 8

尽量比1大,否则在实验的时候,从库增加之类的,会受到限制。

下面是主从切换关键的点:
postgre安装目录的share/postgre目录下将recovery.conf.sample
复制一份到postgre安装目录的data目录下,并且重命名为recovery.done。
比如我的安装目录就是:/opt/PostgreSQL/10/
各位按实际情况。

这个recovery.done是一个很重要的文件,如果命名为recovery.conf文件,那么postgre在启动的时候就是依据这个文件存不存在来判断当前库是主库还是从库的。从库是recovery.conf。

postgre就是通过recovery.conf里面的配置来找到主库的信息。
这里命名为recovery.done是因为当前库是主库,

在recovery.done里面增加配置:

#核心配置
primary_conninfo = 'host=192.168.0.6 port=5432 user=foo password=12345'
standby_mode = 'on'
recovery_target_timeline = 'latest'
#触发切换为主库的文件
trigger_file = '/opt/PostgreSQL/10/data/trigger_file'

primary_conninfo 是从库的信息,为后续主从切换做准备。
trigger_file 非常重要,postgre一旦监听到这个文件的生成,就会自动将recovery.conf修改为recovery.done,并且将数据库只读权限改为读写权限。

从库配置

1.复制主库数据库

使用pg的命令,先将主库的数据库复制过来:

pg_basebackup -D /opt/PostgreSQL/10/data/ -h 192.168.0.33 -p 5432 -U 用户名 -X stream

这里的ip是主库的ip。
执行这条命令之后会让输入密码。

注意:
执行上面的命令后,启动数据库可能会报下面的错误。

CST [32505] DETAIL:  Permissions should be u=rwx (0700).
stopped waiting

这是data文件夹权限导致的。将data文件的权限修改为700。

chmod 700 data
2.配置recovery.conf文件

在data目录下,如果已经存在recovery.done文件,将recovery.done文件修改为recovery.conf文件。
如果不存在,从share/postgre下复制一份过来,重命名为recovery.conf。和上面的一样。
然后增加配置:

#核心配置
primary_conninfo = 'host=192.168.0.33 port=5432 user=foo password=12345'
standby_mode = 'on'
recovery_target_timeline = 'latest'
#触发切换为主库的文件
trigger_file = '/opt/PostgreSQL/10/data/trigger_file'

这里的primary_conninfo 是主库信息,其余不再赘述。

3.主从切换,配置pg_hba.conf文件

增加主库ip

host    replication     all             192.168.0.33/32         md5

到这里,主从搭建完毕。接下来依次启动主库,从库即可。

主从切换

主从切换分两步来说。

  • 从库提升为主库
  • 主库重启降级为从库

剩下的就是如何去实现。
市面上有很多第三方的工具或者集成方案,我这里简单自己通过shell脚本来实现了。并且分析一下思路。

1.从库权限提升

在上面配置的时候已经提到了,pg在启动的时候是根据recovery.conf存不存来判断当前库是主库还是从库的。
在recovery.conf里面有这么一条配置

trigger_file = '/opt/PostgreSQL/10/data/trigger_file'

如果这个文件被触发生成,那么当前库会自动提升为主库。所以我们只需要在从库需要被提升的时候创建这个文件即可。
那么从库什么时候提升呢?
自然就是主库宕机了。
从库又如何知道主库有没有宕机呢?

有很多方案,比如我们可以Telnet 主库ip 5432 ,一旦没有返回值,我们可以认为主库已经宕机。
我们还可以使用psql命令远程查询。如果查询不出来,也可以认为主库宕机。

从库可以每秒去查询一次主库,来判断主库有没有宕机

分析到这里,我们已经可以使用shell来实现了。
下面贴出我自己实现的shell脚本。

. /etc/init.d/functions
if [ $# -ne 5 ]
then
     action "需要主库ip,端口,pg安装的根目录,用户名,密码,以空格隔开 例如:192.168.0.1 5432 /opt/PostgreSQL/10 postgres 12345" /bin/false
     exit
fi

a=$1
b=$2
c=$3
e=$4
f=$5

export PGPASSWORD=$f

while :
do
  num=`echo -n "\n"|$c/bin/psql -h $a -p $b -U $e -d postgres -c "SELECT pg_is_in_recovery from pg_is_in_recovery()"|grep f|wc -l`
  if [ $num -eq 1 ]
  then
     echo "检测正常"
     sleep 1s
  else 
      chmod 777 $c/data/recovery.conf
      echo "检测到主库宕机"
      echo "检测到主库宕机,从库切换" >> pgheart.log
      echo "生成trigger_file" >> $c/data/trigger_file
      break
  fi
done

这个shell脚本主要功能就是每秒去查询一次主库,一旦发现主库不正常,就会触发生成trigger文件,然后提升主库。
为了防止从库提升的时候recovery.conf文件没有操作权限,这里先将recovery.conf的权限给提升。

2.主库重启降级

一:主库再次重启的时候,我们就要求这时候主库应该降级为从库了。
根据上面的分析我们知道,postgre是根据recovery.conf存不存在来判断主从库的。

所以我们首先要确保data目录下有一个recovery.conf。
我们在刚开始配置的时候建立过一个recovery.done文件,里面有配置好的从库的一些信息。这个时候将recovery.done重命名为recovery.conf即可。

附注:如果用nohup &后台执行了脚本,可以使用jobs来查看正在执行中的任务。

二:如果从库已经操作了一部分数据,那么在这个时候主从数据实际上是不一致的。所以我们需要在主库中恢复宕机这一段时间从库新变化的数据。
我们可以通过pg_rewind命令来进行时间线同步。
同步完数据库之后就可以启动pg服务了。
下面给出一个shell脚本的简单实现:

#!/bin/sh
. /etc/init.d/functions
if [ $# -ne 5 ]
then
     action "需要pg服务的根目录,主库ip,端口,用户名,密码。请用postgres用户。例如/opt/PostgreSQL/10 192.168.0.33 5432 postgres 12345" /bin/false
     exit
fi
a=$1
b=$2
c=$3
d=$4
e=$5


#进行recovery.done文件替换
if [ -f "$a/data/recovery.done" ];then
    mv $a/data/recovery.done $a/data/recovery.conf
    action "替换recovery.done文件成功。程序继续执行" /bin/true
    echo "替换recovery.done文件成功。程序继续执行" >> pgslaver.log
else
    action "需要recovery.done监听文件。如果已经存在请忽视" /bin/false
    echo "recovery.done文件不存在" >> pgslaver.log
fi

#进行recovery.conf文件检测
if [ -f "$a/data/recovery.conf" ];then
    action "检测到recovery.conf文件存在。程序正常执行" /bin/true
    echo "检测到recovery.conf文件存在。程序正常执行" >> pgslaver.log
else
    action "检测recovery.conf文件失败,recovery.conf不存在。" /bin/false
    echo "检测recovery.conf文件失败,recovery.conf不存在。" >> pgslaver.log
    exit
fi
#关闭pg服务
echo "关闭pg服务,如果已经关闭请忽略"
su - postgres -c "$a/bin/pg_ctl stop -m fast -w -D '$a/data'"
echo "关闭pg服务结束"

#进行pg_rewind命令同步时间线
echo "进行时间线同步开始"

pg_rewind_result=`su - postgres -c  "$a/bin/pg_rewind  --target-pgdata=/opt/PostgreSQL/10/data --source-server='host=$b port=$c user=$d dbname=postgres password=$e'"`
echo "进行时间线同步结束 结果 -- $pg_rewind_result"

echo "开始启动pg服务"
su - postgres -c "$a/bin/pg_ctl start -m fast -w -D '$a/data'"
echo "启动pg服务结束 "

这个脚本主要目的首先是进行recovery.conf文件的生成。
然后关闭pg的服务,防止pg服务随系统重启了。
然后进行pg_rewind 执行时间线同步。

PS:
在执行pg_rewind 命令的时候我们可以先拿出来远程执行下试试,有可能会报下面这个错。

could not fetch remote file "global/pg_control": ERROR:  must be superuser to read files

Failure, exiting

这是因为进行pg_rewind 的用户在主库上权限不足,没有

SELECT pg_read_binary_file('')

所以执行pg_rewind命令最好使用postgre用户来执行。

附注: 这个shell脚本可能有问题,没有经过严格的测试,大家具体看下设计思路即可。千万不要用于生产环境!

评论
validate