作者:瀚高PG实验室(Highgo PG Lab)-天蝎座

PostgreSQL复制方式有两种:物理复制逻辑复制

早在PG9.0版本开始支持物理复制,也可以叫流复制(Streaming Replication下文中流复制一般指物理流复制)。PG10版本开始支持逻辑复制。

流复制技术可以在实例级别复制出一个与主库一模一样的从库(备库)。通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。而PostgreSQL9.0之前提供的方法是主库写完一个WAL日志文件后,才把WAL日志文件传送到备库,这样的方式导致主备延迟比较大,大概是一个WAL日志文件的大小。PostgreSQL9.0之后还提供了Hot Standby功能,备库在应用WAL record的同时也能够提供只读服务,自此PostgreSQL可以支持读写分离。

逻辑复制通常也称之为选择性复制,他可以做到基于表级别的复制,选择需要逻辑复制的表。

流复制和逻辑复制的区别:

1.流复制支持DDL,逻辑复制不支持DDL

2.流复制备库只读,逻辑复制备库可读写

3.流复制要求大版本一致,逻辑复制支持跨越大版本。

4.流复制只能针对PG实例级进行复制,逻辑复制能够针对数据库表级进行复制。

5.流复制为物理复制,核心原理是主库将WAL流式发送给备库,备库接收到WAL日志后进行重做

逻辑复制核心原理虽然也基于WAL但稍有不同。逻辑复制会根据预先设置好的规则解析WAL日志,将WAL二进制文件解析成一定格式的逻辑变化信息,主库将逻辑变化信息发送给备库,备库接收到WAL逻辑解析信息后再应用。


对于流复制和逻辑复制而言,两者可应用于不同的场景

本系列文章将主要分为以下7个章节介绍:

1. 流复制部署(异步、同步)

2. 流复制监控

3. 流复制主备切换

4. 延迟备库

5. 同步复制优选提交

6. 级联复制

7. 流复制维护生产案例


流复制部署

实验环境:

部署过程如下,主备节点都需要进行操作:
创建用户:
#   groupadd postgres                --创建用户组
#   useradd postgres -g postgres     --创建用户
#   passwd postgres                 --设置postgres用户的密码

创建目录并赋予权限

#   mkdir -p /data/postgres/11/
#   chown -R postgres:postgres /data/postgres/11/

解压软件并安装:

#   tar -zxvf postgresql-11.1.tar.gz
#   cd postgresql-11.1
#   ./configure –prefix=/data/postgres/11/

安装依赖包:

#   yum install zlib readline
#   gmake world
#   gmake install-world

 初始化数据库:

#   su – postgres

备库不需要初始化数据库数据目录,以下参数的修改均在主库执行:
$   initdb -D /data/postgres/11/data -E UTF8 –locale=C -U postgres     
 -- 指定数据库数据目录, -E 指定字符集 -locale 指定区域偏好

数据库安装完成后,需要配置如下所示数据库参数:

wal_level = replica
该参数控制WAL日志信息的输出级别,有minimal,replica,logical三种模式,修改该参数需要重启。
minimal记录的日志最少,只记录数据库异常关闭需要恢复时的WAL信息。
replica记录的WAL信息比minimal信息多些,会记录支持WAL归档、复制和备库中启用只读查询等操作所需的WAL信息。
logical记录的日志最多,包含了支持逻辑解析所需的WAL。
开启流复制至少需要设置为replica级别。

archive_mode = on
该参数控制是否启用归档。On表示启用归档并使用archive_command参数的配置命令将WAL日志归档,修改该参数需要重启数据库。

archive_command = ‘cp %p /data/archivedir/%f’
该参数设置WAL归档命令,可以将WAL归档到本机或者归档到其他主机。流复制并不一定需要配置该参数。你可以声明一个shell命令来拷贝一个完整的WAL文件到它需要去的地方。 该命令可以简单的就是一个cp,或者它可以调用一个复杂的shell脚本。

max_wal_senders = 10
该参数控制主库上的最大WAL发送进程。pg_basebackup命令做基准备份时也会消耗WAL进程,此参数不能比max_connections参数高,默认为10.一个流复制备库通常消耗流复制主库一个WAL发送进程。

wal_keep_segments = 512
该参数设置主库pg_wal(10版本以前是pg_xlog)目录保留的最小WAL日志文件数,以便备库落后主库时可以通过主库保留的WAL进行追回。默认情况下每个WAL文件为16MB(编译时可通过--with-wal-segsize设置WAL文件大小)

hot_standby = on
该参数控制数据库恢复过程中是否启用读操作,这个参数通常用在流复制备库,开启参数后流复制备库支持只读SQL,不支持写。

以上为流复制配置过程中主要的参数,除此以外配置主库的pg_hba.conf:
#replication privilege
hots   replication       repuser 192.168.80.126/32  md5
hots   replication       repuser 192.168.80.127/32  md5

启动pghost1上的数据库:
$ pg_ctl start
使用超级用户postgres登录到数据库创建流复制用户repuser,流复制用户需要有replication和login权限,该部分建议新建流复制专用用户而不是使用超级用户:
create user replica replication login connection limit 5 encrypted password 'replica';
在pghost2以pg_basebackup命令部署流复制:
$ pg_basebackup -D /data/postgres/11 -Fp -Xs -v -P -h 192.168.80.126 -p 5432 -U repuser
pg_basebackup命令执行的操作为将主库的数据目录同步到备节点,保证主备数据目录保持一致。

进入数据库数据目录下,新建recovery.conf文件并配置以下参数:

recovery_target_timeline = 'latest'     
standby_mode = on                            
primary_conninfo = 'host=192.168.80.126 port=5432 user=repuser'
recovery_target_timeline

设置恢复的时间线,latest表示从备份中恢复到最近的时间线
standby_mode
设置是否启用数据库为备库,如果设置为on,备库会不停的从主库上获取WAL日志流,直到获取主库上最新的WAL日志流。

primary_conninfo
参数设置主库的连接信息,设置了主库IP、端口、用户名信息,但没有配置明文密码,在连接串中给出数据库密码不是好习惯,建议将密码配置在隐藏文件~/.pgpass 中。

$ touch ~/.pgpass
$ chmod 0600 ~/.pgpass

.pgpass文件内容分为五部分,分别为:
IP:端口号:数据库名:用户名:密码
192.168.80.126:5432:replication:repuser:repuser
192.168.80.127:5432:replication:repuser:repuser

流复制部署完成后,可通过pg_stat_replication试图的sync_state字段查看流复制状态:

postgres=# select usename,application_name,client_addr,sync_state from pg_stat_replication;
usename  | application_name |  client_addr       | sync_state
-----------+--------------------+-----------------+------------
repuser    |        walreceiver      | 192.168.80.127 | async
(1 row)

sync_state字段的可选项包括:

async:表示备库为异步同步模式
sync: 当前备库为同步模式
potential:表示备库当前为异步同步模式,如果当前的同步备库宕机后,异步备库可升级成为同步备库。
quorum:表示备库为quorum standbys的候选,后面会介绍这个特性。

同步流复制

 前面我们搭建的环境为异步流复制,异步流复制指主库上提交事务时不需要等待备库接收并写入WAL日志就返回成功,如果主库异常宕机,主库上提交的事务可能还没来得及发送给备库,就会造成备库数据丢失。

    同步流复制在主库上提交事务时需要等待备库接收并写入WAL日志,当主库至少收到一个备库发回的确认信息时便返回成功,同步流复制确保了至少一个备库收到了主库发送的WAL日志,一方面保障了数据的完整性,另一方面增加了事务响应时间。

    介绍同步流复制前先介绍一下参数synchronous_commit,理解它的含义能更好的理解同步流复制。

    单实例环境:

    on:    当数据库提交事务时,WAL先写入WAL BUFFER再写入WAL日志文件,设置成on表示提交事务时需等待本地WAL写入WAL日志后才返回成功,设置成on非常安全,但数据库性能有损耗。

    off:    设置成off时也不会带来风险,但是当数据库宕机时最新提交的事务可能会丢失。

    local:    local的含义和on类似,表示提交事务时需等待本地WAL写入后才返回成功。

  流复制环境:

    remote_write:    当流复制提交事务时,需等待备库接收到主库发送的WAL日志流写入备节点操作系统缓存中之后返回成功。备库宕机不会导致事务丢失,但是如果备库操作系统宕机存在事务丢失的风险。本地WAL落盘,备库WAL还在备库操作系统缓存中,只有一份持久化的WAL。

    on:    设置成on表示流复制主库提交事务时,需等待备库接收主库发送的WAL日志流写入WAL文件才返回成功。本地WAL落盘,备库的WAL也已经落盘,有两份持久化的WAL。但此时备库还未完成apply。

    remote_apply:    表示流复制主库提交事务时,需等待备库接收主库发送的WAL并写入WAL文件,同时备库已经完成重做后才返回成功。本地和备库的WAL都已经落盘,有两份持久化的WAL,同时备库也完成了apply。

备库的recovery.conf配置文件设置如下:

primary_conninfo = 'host=192.168.80.126' port=5432 user=repuser application_name=node2'

primary_conninfo参数添加application_name选项,application_name选项指定备节点的别名,主库postgresql.conf的synchronous_standby_names可引用备库application_name选项设置的值,设置成node2。

主库上postgresql.conf配置文件设置为以下参数,其他参数与异步流复制配置一致。

synchronous_commit = on或者remote_apply

synchronous_standby_names = 'node2'

主库查看复制状态,如下所示:

postgres=# select usename,application_name,client_addr,sync_state from pg_stat_replication;
usename  | application_name |  client_addr       | sync_state
---------+------------------+--------------------+------------
repuser  |     node2        | 192.168.80.127     | sync
(1 row)

同步流复制“陷阱”:

在同步流复制中由于主库提交事务时需等待至少一个备库接收WAL并返回确认信息后主库才返回成功。基于以上前提,若备库宕机,则主库所有

写操作将被阻塞。所以若生产环境为一主一备,不应使用同步流复制。 一主多从的情况下可以选择一主多从。