暂无图片
暂无图片
6
暂无图片
暂无图片
暂无图片

PostgreSQL12.8 部署流复制

原创 贾勇智 2021-10-18
2934

概述:

物理复制,也称为流复制,通过流复制技术可以从实例级复制出一个与主库模一样的从库。流复制通常有两种方式,同步、异步两种,主备库间延迟时间能控制在毫秒级。

逻辑复制,也称为选择性复制,基于表级别的复制,选择需要逻辑复制的表。从postgesql10 开始支持内置的逻辑复制。

WAL(Write-Ahead-Logging)日志记录数据库的变化,格式为二进制格式,当主机出现异常断电时如果WAL文件已经写入成功,但还没有来得级刷新数据文件,当数据库再次启动时会根据WAL日志文件信息进行事务前滚,从而恢复数据库到一致性状态。

尽管流复制和逻辑复制都是基于WAL,但两者有本质的不同,流复制是基于WAL物理复制,逻辑复制是基于WAL逻辑解析,将WAL解析成一种清晰、易于理解的格式。

流复制与逻辑复制的差异:


流复制

逻辑复制

实例级

表级

可对表DD操作复制

DDL操作不会复制到备库

主库可读写,从库只读

主从库都可读写

PostgreSQL大版本必须一致

支持跨PostgreSQL大版本

原理:主库将预写日志WAL日志流发磅给备库,备库接收到WAL日志流后进行重做,因此复制是基于WAL日志文件的物理复制。

原理:也是基于WAL,逻辑复制会根据预先设置好的规则解析WAL日志,将WAL二进制文件解析成一定格式的逻辑变化信息。

1.异步流复制

异步流复制是指主库上提交事务时不需要等待备库接收WAL日志流并写入到备库WAL日志文件时便返回成功,而同步流复制相反。

这一小节内容主要介绍PostgreSQL异步流复制的部署,异步流复制部署主要有两种方式,一种试是拷贝数据文件方式,另一种方式是通过pg_basebackup命令行工具,这两种方式的绝大部分部署步骤都一样,只是数据复制方式不同。

流复制试验环境:

主机

主机名

IP地址

操作系统

PosgreSQL版本

主节点

pg01

192.168.150.161

CentOS Linux release 7.6.1810 (Core)

(PostgreSQL) 12.8

备节点

pg02

192.168.150.162

CentOS Linux release 8.4.2105

(PostgreSQL) 12.8

备节点

pg03

192.168.150.163

CentOS Linux release 8.4.2105

(PostgreSQL) 12.8

第一种方式:以拷贝数据文件方式部署流复制

PostgreSQL安装:请看文章《CentOS8.4 源码安装PostgreSQL12.8》https://www.modb.pro/db/125909

初始化数据实例:请看文章《PostgreSQL12.8 创建数据库实例,并启动停止服务的三种方法》https://www.modb.pro/db/129030


初始化后配置流复制相关的参数:

wal_level = replica # minimal, replica, or logical

archive_mode = on # enables archiving; off, on, or always

archive_command = 'cp "%p" "/pgdata02/12/archive/%f"' # command to use to archive a logfile segment

max_wal_senders = 10 # max number of walsender processes

wal_keep_segments = 512 # in logfile segments; 0 disables

hot_standby = on # "off" disallows queries during recovery

以上几个postgresql.conf参数是流复制的主要参数:

wal_level参数控制WAL日志输出级别,有minimal replica logical三种模式。调整此参数需要重启数据库生效,开启流复制至少需要为replica级别。

archive_mode参数控制是否启用归档,off表示不记用归档,on表示启用归档并使用archive_command参数的配置命令将WAL日志归档到归档存储上,此参数设置需重启数据库生效,通常设置成on。

archive_command参数设置WAL归档命令,可以将WAL归档到本机目录,也可以归档到远程主机上。

max_wal_senders参数控制主库上的最大WAL发送进程数,通过pg_basebackup命令在主库上做基准备份时也会消耗WAL进程,此参数设置不能比max_connection参数值高,默认为10,一个流复制备库通常只需要消耗流复制主库一个WAL发送进程。

wal_keep_segments参数设置主库pg_wal目录保留的最小WAL日志文件数,以便备库落后主库时可以通过主库保留的WAL进行追回,这个参数设置的越大,理论上备库在异常断开时追平主库的机率越大,如果归档存储空间充足,建议将此参数配置得大些,由于默认情况下每个WAL文件为16MB(编译时可通过--with-wal-segsize参数设置WAL文件大小),因此pg_wal目录大概占用空间为wal_keep_segments参数值*16MB,这里为512*16MB=8GB,实际情况下pg_wal目录下的WAL文件数会比此参数的值稍大些。

hot_standby参数控制数据库恢复过程中是否启用读操作,这个参数通常用在流复制备库,开启此参数后流复制备库支持只读SQL,但备库不支持写操作,主库和备库的postgresql.conf配置建议完全一致。



使用超级用户创建专门的流复制用户repuser,流复制用户需要有replication权限和login权限,如下所示:

postgres@[local]:1931=#create user repuser

postgres-# replication

postgres-# login

postgres-# connection limit 5

postgres-# encrypted password 'pg12ps345';

CREATE ROLE


以上完成主库的配置,接下热备生成一个备库,制作备库过程中主库仍然可读写,不影响主库上的业务,以postgres超级用户执行以下命令:

postgres@[local]:1931=#select pg_start_backup('pg12_bk1');

pg_start_backup

-----------------

0/E000028

(1 row)


pg_start_backup()函数在主库上发起一个在线备份,命令执行成功后,将数据文件拷贝到备节点pg02,pg03,如下所示:

tar czvf data.tar.gz data --exclude=data/pg_wal

scp data.tar.gz 192.168.150.163:/

tar -cvf pg_wal.tar pg_wal


pg_wal目录不是必须复制的,如果pg_wal目录下文件比较多,压缩包时可以排除这个目录,以节省数据拷贝时间,数据拷贝到备节点后,备节点的pg_wal目录需要手工创建,如果有另外的表空间目录也需要拷贝。

之后在pg02,pg03解压文件,如下所示:

[root@pg03 12]# tar -xvf data.tar.gz

文件拷贝到备节点后,在主库上执行以下命令,停止在线备份状态:

postgres@[local]:1931=#select pg_stop_backup();

NOTICE: all required WAL segments have been archived

pg_stop_backup

----------------

0/3000170

(1 row)


以上命令表示完成在线备份,在备库上配置以下参数:

recovery_target_timeline='latest'

standby_mode=on

primary_conninfo='host=192.168.150.161 port=1931 user=repuser password=123456'


特别重要的是:在备库数据目录下使用系统命令touch生成文件standby.signal表示它是备库,如果无此文件,表示是主库。参考书籍是postgresql 10 的,pg 10 使用recovery.conf文件表示备库,pg12后,取消recovery.conf文件,将参数合并到postgresql.conf文件中。

To set up the standby server, restore the base backup taken from primary server (see Section 25.3.4). Create a file standby.signal in the standby's cluster data directory. Set restore_command to a simple command to copy files from the WAL archive. If you plan to have multiple standby servers for high availability purposes, make sure that recovery_target_timeline is set to latest (the default), to make the standby server follow the timeline change that occurs at failover to another standby.


启动备库:

[postgres@pg03 data]$ pg_ctl start

。。。

done

server started


成功后,在主库查看备库信息:

postgres@[local]:1931=#\x

Expanded display is on.

postgres@[local]:1931=#select * from pg_stat_replication;


第二种方式:以pg_basebackup方式部署流复制

停止备库,删除备库。

pg_ctl stop

rm -rf /pgdata02/12/data

首先在pg02上执行一个基础备份:

[postgres@pg02 12]$ pg_basebackup -D /pgdata02/12/data -Fp -Xs -v -P -h 192.168.150.161 -p 1931 -U repuser

pg_basebackup: initiating base backup, waiting for checkpoint to complete

pg_basebackup: checkpoint completed

pg_basebackup: write-ahead log start point: 0/10000028 on timeline 1

pg_basebackup: starting background WAL receiver

pg_basebackup: created temporary replication slot "pg_basebackup_11649"

24598/24598 kB (100%), 1/1 tablespace

pg_basebackup: write-ahead log end point: 0/10000100

pg_basebackup: waiting for background process to finish streaming ...

pg_basebackup: syncing data to disk ...

pg_basebackup: base backup completed


从上看,首先做了一次checkpoint,之后基于时间点做了一个全库备份。

之后需要使用系统命令生成代表备库的文件standby.signa,同时备primary_conninfo参数。

启动备库:

[postgres@pg02 data]$ pg_ctl start

。。。

done

server started


在主库查看备库信息:

postgres@[local]:1931=#select * from pg_stat_replication;


2.同步流复制

在异步流复制的基础上,进行配置:

第一步,配置主库:

synchronous_standby_names = 'pg02,pg03'

第二步:配置备库:

primary_conninfo = 'application_name=pg02 host=192.168.150.161 port=1931 user=repuser password=123456'

primary_conninfo = 'application_name=pg03 host=192.168.150.161 port=1931 user=repuser password=123456'

第三步:重启备库,重新加载主库:

pg_ctl restart

pg_ctl reload

第四步:查看主库库同步状态:

postgres@[local]:1931=#select application_name,client_addr,sync_priority,sync_state from pg_stat_replication;

application_name | client_addr | sync_priority | sync_state

------------------+-----------------+---------------+------------

pg02 | 192.168.150.162 | 1 | sync

pg03 | 192.168.150.163 | 2 | potential

从上可以看到备库,pg02是同步状态“sync",pg03状态是”potential",表示是潜在的同步库。


测试同步状态变化:

停掉pg02后,pg03自动变成同步状态,如下所示:

[postgres@pg02 data]$ pg_ctl stop

done

server stopped

postgres@[local]:1931=#select application_name,client_addr,sync_priority,sync_state from pg_stat_replication;

application_name | client_addr | sync_priority | sync_state

------------------+-----------------+---------------+------------

pg03 | 192.168.150.163 | 2 | sync



再次启动pg02,pg02成为同步状态,pg03成为备用同步状态。

[postgres@pg02 data]$ pg_ctl start

...

done

server started

postgres@[local]:1931=#select application_name,client_addr,sync_priority,sync_state from pg_stat_replication;

application_name | client_addr | sync_priority | sync_state

------------------+-----------------+---------------+------------

pg02 | 192.168.150.162 | 1 | sync

pg03 | 192.168.150.163 | 2 | potential

(2 rows)

将库配置成两个同步节点:

synchronous_standby_names = '2(pg02,pg03)' # standby servers that provide sync rep

重新加载主库:

[postgres@pg01 data]$ pg_ctl reload

server signaled

。。。


查看备库同步状态,成为两个同步:

postgres@[local]:1931=#select application_name,client_addr,sync_priority,sync_state from pg_stat_replication;

application_name | client_addr | sync_priority | sync_state

------------------+-----------------+---------------+------------

pg02 | 192.168.150.162 | 1 | sync

pg03 | 192.168.150.163 | 2 | sync

(2 rows)

测试当一个备库停止后,主库是事可以写入:

备库:

[postgres@pg02 data]$ pg_ctl stop

。。。

done

server stopped


主库写入Hang住:

postgres@[local]:1931=#insert into test_sr values (6);




这时启动备库:

[postgres@pg02 data]$ pg_ctl start

。。。

done

server started


主库:

postgres@[local]:1931=#insert into test_sr values (6);

2021-10-18 11:13:31.449 CST [13722] LOG: standby "pg02" is now a synchronous standby with priority 1

2021-10-18 11:13:31.449 CST [13722] STATEMENT: START_REPLICATION 0/14000000 TIMELINE 1

INSERT 0 1


备库验证是否写入数据:

postgres=# select * from test_sr;

id

----

2

5

6

(3 rows)



配置quorum模式的两个同步节点的情况:

将主库参数synchronous_standby_names进行如下配置,重新加载reload生效:

synchronous_standby_names = 'any 2(pg02,pg03,pg04)' # standby servers that provide sync rep

[postgres@pg01 data]$ pg_ctl reload

server signaled


查看同步状态,发现各个节点优先级都一样,同步状态都变成了quorum,这时停掉一个备库,主库还是正常写入:

postgres@[local]:1931=#select application_name,client_addr,sync_priority,sync_state from pg_stat_replication;

application_name | client_addr | sync_priority | sync_state

------------------+-----------------+---------------+------------

pg04 | 192.168.150.164 | 1 | quorum

pg02 | 192.168.150.162 | 1 | quorum

pg03 | 192.168.150.163 | 1 | quorum

(3 rows)

至此,流复制的同步与异步,配置完成,初学不到之处多,请喷。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论