1 简介
主节点持续归档/传送 WAL,备节点持续恢复/接收 WAL 并应用,以此实现一个高可用集群,这种方式叫做 log shipping
,这样的备节点也叫做 warm standby
,如果备节点接受 只读查询
,则叫做 hot standby
。
PostgreSQL 支持 2 种级别的 log shipping
:
文件级(file-based):主节点配置
archive_command
持续归档 WAL 文件,备节点配置restore_command
持续恢复 WAL 文件并应用。记录级(record-based): 主节点持续传送 WAL 记录,备节点持续接收 WAL 记录并应用,即
流复制(streaming replication)
。
2 环境要求
硬件:主备节点之间的 CPU 架构必须相同(不同架构下的数据类型长度可能不同,从而导致存储结构的差异)。
版本:主备节点之间的 major 版本必须相同(minor 版本可以不同,通常 minor 版本之间的存储结构不发生变化,但是官方不对此做正式保证,所以建议主备之间版本尽量一致;如果需要升级整个集群的 minor 版本,建议先升级备节点,再升级主节点)。
表空间(TABLESPACE):主备节点之间必须存在相同的表空间路径。
3 备节点基本原理
当一个数据库实例的数据目录(datadir)下存在 standby.signal
文件时,该实例启动时则进入 备节点模式(standby mode)
。
备节点模式下启动,数据库按照如下顺序读取 WAL 并应用:
如果配置了
restore_command
,则调用 restore_command 从归档中恢复 WAL 并应用直到 restore_command 失败为止。然后读取
pg_wal
目录中的所有可用 WAL 并应用直到结束;然后,如果配置了流复制,则通过流复制从主节点持续接收 WAL 并应用;
如果流复制断开,则重新从第 1 步开始,如此往复;
当备节点执行升主操作(pg_ctl promote
或调用 pg_promote()
函数)后,则退出备节点模式,但是在升主前,会把 归档
和 pg_wal
中的可用 WAL 都先应用了。
4 文件级(持续归档和恢复)
4.1 主节点配置
配置
archive_mode
参数为on
。配置
archive_command
参数来持续归档 WAL 到一个即使主节点挂掉了,备节点也能访问的地方,可以是第一个第三方节点或者就在备节点上。
4.2 备节点配置
使用
pg_basebackup
命令从主节点拉取数据目录,如pg_basebackup -P -h <PRIMARY_NODE_IP> -U <REPLICATION_USER> -p <DBPORT> -D <DATADIR>
。配置
restore_command
参数来从归档持续恢复 WAL 文件并应用。配置
archive_mode
和archive_command
参数和主节点一样,以备当前备节点提升为主节点后能继续归档(除非archive_mode
为always
,否则备节点模式下不会执行归档命令)。配置
recovery_target_timeline
为latest
(默认值),以此保证当发生切主到其他备节点时,当前备节点能及时跟随新主。如果只有一主一备,则可以同时在
archive_cleanup_command
参数中调用pg_archivecleanup
命令来自动清理当前备节点已不再需要的 WAL 文件。在数据目录下创建
standby.signal
文件并启动数据库。
4.3 备节点配置持续归档
当 archive_mode
参数配置为 always
时,备节点模式下仍然会执行 archive_command
来归档 WAL 文件。这通常用在级联复制的上游(upstream)备节点中,用于给下游(downstream)备节点提供归档。
5 记录级(流复制)
5.1 主节点配置
配置
listen_addresses
参数为包括备节点 IP 的范围,如*
。创建一个带
REPLICATION
权限的用户,如CREATE USER <REPLICATION_USER> PASSWORD '<REPLICATION_PWD>' REPLICATION;
。在
pg_hba.conf
文件中增加允许备节点访问的配置,如host replication replica <STANDBY_NODE_IP>/32 md5
(database
列配置为虚拟数据库名replication
)。配置
max_wal_senders
参数为足够所有备节点使用的值。为了防止 WAL 文件在备节点接收前被回收,可以配置
wal_keep_size
参数或 复制槽 来为备节点保留 WAL。在支持
socket keepalive
的系统上,可以配置tcp_keepalives_idle
、tcp_keepalives_interval
和tcp_keepalives_count
这几个参数来帮助主节点及时发现流复制连接断开情况。
5.2 备节点配置
使用
pg_basebackup
命令从主节点拉取数据目录,如pg_basebackup -P -h <PRIMARY_NODE_IP> -U <REPLICATION_USER> -p <DBPORT> -D <DATADIR>
。配置
primary_conninfo
参数连接到主节点,如primary_conninfo = 'host=<PRIMARY_NODE_IP> port=<DBPORT> user=<REPLICATION_USER> password=<REPLICATION_PWD>'
。在数据目录下创建
standby.signal
文件并启动数据库。启动并连接成功后,可以在备节点看到一个
walreceiver
进程,还可以在主节点看到一个walsender
进程。
5.3 复制槽
如果流复制备节点连接断开后过了较长时间才恢复连接,那么有些还没有被备节点接收的 WAL 文件可能在主节点已经被回收,导致备节点无法追赶(catch-up)上主节点。我们可以通过配置 wal_keep_size
参数或 复制槽
来避免该问题。但是配置 wal_keep_size
的方式需要估计一个比实际需要保存更大的值,这样就会又些冗余文件的方式,而 复制槽
的方式则更精确,仅保留未被绑定到该复制槽上的备节点们接收的 WAL 文件。
需要注意的是配置复制槽后,如果备节点长期离线,可能会导致主节点积压过多的 WAL 文件而占用大量空间,为了避免该问题,可以配置 max_slot_wal_keep_size
参数来限制保留的最大值。
可以通过 流复制协议 或 相关 SQL 函数 来创建管理复制槽,比如:
1
2
3
4
5
6
7
8
9
10
postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
slot_name | lsn
-------------+-----
node_a_slot |
postgres=# SELECT slot_name, slot_type, active FROM pg_replication_slots;
slot_name | slot_type | active
-------------+-----------+--------
node_a_slot | physical | f
(1 row)
备节点通过配置 primary_slot_name
参数来绑定复制槽,比如:
1
primary_slot_name = 'node_a_slot'
5.4 级联复制
备节点可以不连接主节点而连接其他备节点并接收 WAL,这样所组成的多级流复制拓扑就是 级联复制(cascading replication)
,这样可以减少主节点的连接数量以此减少主节点的带宽占用。
级联复制的层级数量不受限制,更靠近主节点一端备节点被称为 上游节点(upstream)
,离主节点更远一端的节点则被称为 下游节点(downstream)
,一个备节点可以有多个下游,但是只能有一个上游(流复制本身也只能连接到一个发送方,即只能配置一个 primary_conninfo)。
级联复制中的上游节点不仅发送自己接收到的 WAL,如果配置了持续恢复(restore_command),还会发送恢复出来的 WAL(主节点不会,因为主节点不会执行 restore_command),所以即使上游节点与更上游节点的连接断开,只要有持续恢复出来的新的可用的 WAL,还是会继续向下游节点发送(也就是说上游节点可以是 file-based
方式的备节点)。
级联复制中只有 直接备节点(直连到主节点)
支持同步,其他 间接备节点
只能是异步的,就算是在主节点 synchronous_standby_names
参数中指定了级联复制中的间接备节点也不会产生作用。
如果级联复制备节点中开启了 hot_standby_feedback
参数,那么该备节点的 feedback
消息会逐级往上传播直到主节点。
如果上游节点提升为了主节点,下游节点在配置 recovery_target_timeline
参数为 latest
(默认值)的情况下,会自动跟随新主。
要使用级联复制,上游节点除了需要像主节点一样的相关配置(listen_addresses
、pg_hba.conf
、max_wal_senders
、wal_keep_size
或复制槽)之外,还需要配置 hot_standby
参数为 on
(也就是设置为热备),因为备节点的流复制连接需要进行一些必要的只读查询。
5.5 同步复制(synchronous replication)
流复制默认是 异步(asynchronous)
的,即一个事物在主节点提交后如果马上去备节点查询,有可能还查询不到,因为 WAL 记录可能还没有传送到备节点或者备节点还没有回放(replay)该记录。
可以把一个或多个备节点指定为 同步(synchronous)
备节点,配置了同步备节点的流复制集群,在事务提交时需要 一直等待
直到收到同步备节点回复的 WAL 记录已保存的消息后,才返回成功。
以下情况不需要等待同步备节点回复:
- 只读事务(read-only transactions)
- 事务回滚(transaction rollbacks)
- 子事务(subtransaction)
- 数据载入(data loading)
- 索引构建(index building)
同步备节点可以是 物理(流)复制备节点(physical/stream replication standby)
,也可以是 逻辑复制订阅者(logical replication subscriber)
,也可以是其他一些第三方程序,比如 pg_receivewal
和 pg_recvlogical
等。
5.6 状态查询
6 文件级 + 记录级
7 热备(hot standby)
8 故障转移(failover)
9 参考资料
- [High Availability, Load Balancing, and Replication] : https://www.postgresql.org/docs/17/high-availability.html