作者:瀚高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并返回确认信息后主库才返回成功。基于以上前提,若备库宕机,则主库所有
写操作将被阻塞。所以若生产环境为一主一备,不应使用同步流复制。 一主多从的情况下可以选择一主多从。