PostgreSQL 12 流复制实现主从数据库

Published: 2019-12-26

Tags: PostgreSQL

本文总阅读量

概要

组内项目使用 PostgreSQL,因为读写压力较大,决定先初步使用主从模式,主数据库写入,从库负责读取,从而降低单数据库压力,在网上找了一圈,发现中文互联网的教程较老,新版的 PostgreSQL 12 的配置方式已变更,recovery.conf 文件不再被支持,于是查阅资料,整理了基于 Docker 的 PostgreSQL 12 主从配置,新版本的配置非常简便,文末有一键部署脚本命令,可跳过文章直接使用

前置条件

  • 准备两个 Linux 服务器(可使用虚拟机)
  • 已经安装 Docker

本次测试部署主服务器IP:192.168.3.160,从库IP:192.168.3.135

首先,分别在两个服务器上创建 PostgreSQL 容器服务

docker run --name postgres --shm-size=512M -v /opt/pg-data/:/var/lib/postgresql/data/ --restart=unless-stopped -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres:latest

将数据库的数据目录映射到物理机的 /opt/pg-data 下,方便物理机访问

Master 配置

1,创建用于同步数据的用户

docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -c \"CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'secret';\""

此处创建了名为 replicator 的用户,它的密码为 secret (直接使用 postgres 用户也是可以的但不推荐)

2,允许从库连接到主库

echo "host replication replicator 192.168.3.135/32 md5" >> /opt/pg_data/pg_hba.conf

3,重载配置

docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -c \"select pg_reload_conf()\""

主库配置完成

Slave(Standby) 配置

1,移除所有从库数据文件

docker exec -it postgres /bin/sh -c "rm -rf /opt/pg-data/*"

删除从库数据目录下的所有文件,其目的是为同步主库做准备,否则同步数据时会发现主库与从库的校验不一致导致同步数据失败

2,复制主库基础数据

docker exec -it postgres /bin/sh -c "export PGPASSWORD=secret && pg_basebackup -h 192.168.3.160 -U replicator -p 5432 -D /var/lib/postgresql/data -Fp -Xs -P -R"

使用 pg_basebackup 工具来同步基础数据,参数 -R 会在数据目录下新建 standby.signal 文件,这个文件表示本数据库作为备份库存在,其只能读取,无法更新和写入,同样,设置了 -R 参数后,同步工具会自动添加配置信息,配置文件及内容如下

[root@centos7 ~]# cat /opt/pg-data/postgresql.auto.conf 
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
primary_conninfo = 'user=replicator password=secret host=192.168.3.160 port=5432 sslmode=prefer sslcompression=0 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'

primary_conninfo 保存着连接到主库同步数据的配置信息

使用 pg_basebackup 工具很方便,但你依然可以使用 scprsync 工具来将主库映射目录(/opt/pg-data/) 内的数据全部复制到从库的同目录下,然后使用 touch 命令手动创建 /opt/pg-data/standby.signal 文件,并手动编辑 postgresql.auto.conf 文件添加 primary_conninfo 信息

从库配置完成

检验部署

稍等片刻(5 ~ 10s),在主库所在机器上执行如下命令

docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -x -c \"select * from pg_stat_replication\""

输出如下

-[ RECORD 1 ]----+------------------------------
pid              | 286
usesysid         | 16384
usename          | replicator
application_name | walreceiver
client_addr      | 192.168.3.135
client_hostname  | 
client_port      | 39548
backend_start    | 2019-12-26 06:00:41.067925+00
backend_xmin     | 
state            | streaming
sent_lsn         | 0/501AC48
write_lsn        | 0/501AC48
flush_lsn        | 0/501AC48
replay_lsn       | 0/501AC48
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0
sync_state       | async
reply_time       | 2019-12-26 11:24:31.744954+00

有输出则代表主从数据库配置完成,可在主库修改数据,在从库查看变更

一键安装脚本

master_deploy.sh

#!/bin/bash

SLAVE_IP="192.168.3.135" # 填写从库服务器的IP
PGDATA="/opt/pg-data"

# 创建PostgreSQL容器
docker run --name postgres --shm-size=512M -v /opt/pg-data/:/var/lib/postgresql/data/ --restart=unless-stopped -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres:latest

# 休息5s等待容器启动完毕
sleep 5

# 创建用户
docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -c \"CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'secret';\""

# 允许从数据库连接到master
echo "host replication replicator $SLAVE_IP/32 md5" >> $PGDATA/pg_hba.conf

# 重新载入配置
docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -c \"select pg_reload_conf()\""

# 查询
#docker exec -it postgres /bin/sh -c "export PGPASSWORD=postgres && psql -U postgres -x -c \"select * from pg_stat_replication\""

slave_deploy.sh

#!/bin/bash

MASTER_IP="192.168.3.160" # 填写主库服务器的IP
PGDATA_OUT="/opt/pg-data"
PGDATA_IN="/var/lib/postgresql/data"

# 创建PostgreSQL容器
docker run --name postgres --shm-size=512M --net hylink -v /opt/pg-data/:/var/lib/postgresql/data/ --restart=unless-stopped -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres:latest

sleep 5

# 移除从数据库所有数据
docker exec -it postgres /bin/sh -c "rm -rf $PGDATA_IN/*"

# 同步数据(如果是新建的容器,则不用使用这个来同步数据,你可以使用任意方式rsync,scp来复制pgdata下的数据)
# 确保standby.signal文件的存在,pg_basebackup -R 会自动创建,也可以简单的使用touch创建
docker exec -it postgres /bin/sh -c "export PGPASSWORD=secret && pg_basebackup -h $MASTER_IP -U replicator -p 5432 -D $PGDATA_IN -Fp -Xs -P -R"

相较于之前的版本,PostgreSQL 12 进一步简化了配置,清晰且易于部署。

参考

  1. How to Set Up Streaming Replication in PostgreSQL 12