Skip to content

搭建基于流复制 PostgreSQL 主备容器集群

概述

PostgreSQL 内置提供了基于流复制实现主备集群能力,使用场景:

  • 防单点故障
  • 读写分离提升 I/O 性能

流复制集群包含:

  • 主节点 primary server:提供读写
  • 备节点 standby server:提供只读查询;备节点在主故障时也可以提升为主

组成物理复制(physical replication)主备节点要求

  • select version() 输出版本号为中 major.minor major 要一致,如 16.116.2 两个节点可以同步,14.116.1 不可以
  • 节点机器同架构,32 位和 32 位可以,64 位和 64 位可以,32 和 64 位不可以。

注:如果想不同版本和架构节点间同步,需用 Logical Replication (逻辑复制) .

工作原理:TBD.

后面以容器环境搭建为例:

  • Ubuntu LTS docker
  • PostgreSQL 16.x
  • 主节点主机 ip 10.0.0.1
  • 备节点主机 ip 10.0.0.2

创建主节点

宿主机执行 docker pull postgres:16 下载 pg 最新镜像

生成主节点 pg 实例配置

shell
sudo mkdir -p /data/pg1
sudo docker run -i --rm postgres:16 cat /usr/share/postgresql/postgresql.conf.sample > /data/pg1/postgresql.conf

按需修改,如

txt
# 通用配置
listen_addresses = '*'

logging_collector = on
log_directory = '/var/log/postgresql'
log_min_messages = info
log_min_duration_statement = 500

# 主备集群相关配置
wal_level = replica
max_wal_senders = 10
wal_keep_size = '1GB'
wal_compression = on

创建 pg 主节点容器实例

shell
sudo docker run \
--name pg1 \
-p 5432:5432 \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_HOST_AUTH_METHOD=md5 \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v /data/pg1:/var/lib/postgresql/data \
postgres:16 -c 'config_file=/var/lib/postgresql/data/postgresql.conf'

参数说明

  • 环境变量 POSTGRES_HOST_AUTH_METHOD 主机认证方法;
  • 环境变量 POSTGRES_DB 创建名为 postgres 数据库;
  • 环境变量 POSTGRES_USER 创建名为 postgres 用户名 ;
  • 环境变量 PGDATA 自定义数据存储路径
  • 启动参数 -c 指定主配置文件。注:当指定时它所在目录不能和 PGDATA 目录相同,否则会报 PGDATA 不为空(由于目录里面存在配置文件)初始化失败

确认服务启动成功 docker exec -it pg1 psql -h localhost -U postgres -p 5432 -d postgres -c 'select version()'

设置主节点集群相关配置

在主节点 上执行

  • 创建同步账户 repl CREATE ROLE repl login replication encrypted password 'secret';
  • 按需修改 pg_hba.conf 设置权限 host replication repl 10.0.0.1/24 md5
  • 应用权限配置,连接 pg 实例执行 SELECT pg_reload_conf();

在从节点或宿主机上执行,测试同步账号 PGPASSWORD="secret" psql -h localhost -p 5432 -U repl -d postgres

在主节点 pg 实例上执行,创建 replication slot

sql
select * from pg_create_physical_replication_slot('repl01');
select slot_name, slot_type, active, wal_status from pg_replication_slots;

注:slot 不支持改名,可重建 select * from pg_drop_replication_slot('repl01');

创建备节点

宿主机执行 docker pull postgres 下载 pg 最新镜像

生成备节点 pg 实例临时配置

shell
sudo mkdir -p /data/pg2
sudo docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > /data/pg2/postgresql.conf

创建 pg 备节点容器临时实例,注:临时节点指定 PGDATA 数据路径有 .tmp 后缀

txt
sudo docker run \
--name pg2 \
-p 5433:5432 \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_HOST_AUTH_METHOD=md5 \
-e PGDATA=/var/lib/postgresql/data/pgdata.tmp \
-v /data/pg2:/var/lib/postgresql/data \
postgres:16 -c 'config_file=/var/lib/postgresql/data/postgresql.conf'

进入 pg 备节点容器临时实例 shell,从主节点复制集群依赖数据

shell
docker exec -it pg2 /bin/bash

PGPASSWORD=secret \
pg_basebackup \
--pgdata /var/lib/postgresql/data/pgdata \
--format=p \
--write-recovery-conf \
--checkpoint=fast \
--label=mffb \
--progress \
--host=10.0.0.1 \
--port=5433 \
--username=repl

如果备节点无法访问主节点,留意主节点日志错误提示,按需修改 主认证配置文件。

示例提示错误:

2049-05-19 09:06:24.100 GMT [153] FATAL: no pg_hba.conf entry for replication connection from host "172.17.0.1", user "repl", no encryption

则修改住认证配置文件 pg_hba.conf ,补 host replication repl 172.17.0.1/32 md5

退出 shell 并删除临时 pg 容器实例

shell
sudo docker stop pg2
sudo docker rm mypg2

修改备节点配置

shell
cp /data/pg2/postgresql.conf /data/pg2/postgresql.conf.bak
cp /data/pg2/pgdata/postgresql.auto.conf /data/pg2/postgresql.conf

# 以下两个文件内容可参考主节点
touch /data/pg2/pgdata/pg_ident.conf
touch /data/pg2/pgdata/pg_hba.conf

修改从节点主配置文件 /data/pg2/postgresql.conf

txt
primary_conninfo = 'user=repl port=5432 host=10.0.0.2 password=secret'
primary_slot_name = 'repl01'

listen_addresses = '*'

logging_collector = on
log_directory = '/var/log/postgresql'
log_min_messages = info
log_min_duration_statement = 500

创建备节点 pg 容器实例

shell
sudo docker run \
--name pg2 \
-p 5433:5432 \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=postgres \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_HOST_AUTH_METHOD=md5 \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v /data/pg2:/var/lib/postgresql/data \
postgres:16 -c 'config_file=/var/lib/postgresql/data/postgresql.conf'

另开一终端,连接主节点上执行确认复制状态。

方法一:select slot_name, slot_type, active, wal_status from pg_replication_slots;

txt
 slot_name | slot_type | active | wal_status
-----------+-----------+--------+------------
 repl01    | physical  | t      | reserved
(1 row)

输出说明

  • slot_type The slot type: physical or logical
  • reserved means that the claimed files are within max_wal_size.
  • active True if this slot is currently actively being used

方法二:select * from pg_stat_replication;

txt
pid              | 3714690
usesysid         | 16505
usename          | repl
application_name | 14/main
client_addr      | 10.0.0.2
client_hostname  |
client_port      | 47772
backend_start    | 2049-01-23 20:13:24.429329+08
backend_xmin     |
state            | streaming
sent_lsn         | 4B/E8080518
write_lsn        | 4B/E8080518
flush_lsn        | 4B/E8080518
replay_lsn       | 4B/E8080518
write_lag        |
flush_lag        |
replay_lag       |
sync_priority    | 0
sync_state       | async
reply_time       | 2049-01-23 20:28:07.26646+08

write_lag flush_lag replay_lag 三列字段如果为非空表示同步有延迟。

测试在主节点上插入新数据

sql
create table t1 (id int) ;
insert into t1 (id) values (1);

在备上查询 select * from t1; 确认同步正常。

注:默认备节点是只读(read-only)模式,只允许查数据不允许写入数据。

参考

Released under the CC-BY-NC-4.0