Postgresql官方文档关于HA方案的介绍

方案比较

Postgresql官方文档对目前所有的HA方案进行了整理,并列举了典型的实现。

https://www.postgresql.org/docs/11/different-replication-solutions.html

1.数据共享型

目录共享方案包括:Shared Disk Failover和File System (Block Device) Replication。

这种方案只运行单个实例,但是将DB数据存储在共享磁盘上或者通过其他方式实时同步DB数据。当Postgresql实例故障后,用户可以通过共享数据/或者备份数据运行新实例。

可以通过NAS/DRBD实现上述方案。

2.WAL同步

通过追踪Master实例的WAL记录,备机可以Synchronous或Asynchronous保持数据一致性。

WAL包括:File-based Replication和Streaming Replication,两种模式在Postgresql中均有原生支持。

基于WAL同步时,用户在Postgresql实例级别进行HA!

3.Logical Replication

Local Replication相比WAL同步,提供了基于表级别的同步。

该方案中实例基于WAL修改生成Logical Streaming传输到其他实例,实例之间没有主备之分。

Postgresql自10开始提供了Logical Replication功能,在此之前用户可以通过pglogical实现类似能力。

4.插件/中间件方案

插件/中间件主要依赖"拦截/广播SQL语句"或者"触发器"工作,比较出名的包括以下几个:

  • Londiste/Slony:基于触发器工作,可以实现表级别的数据异步复制。
  • pgpool-II:基于"拦截/广播SQL语句"
  • Bucardo:基于触发器工作,是一个异步的多Master方案,主要用在对实时性要求不高的场景。

PITR

PITR全称是Continuous Archiving and Point-in-Time Recovery,是Postgres提供的一种持续在pg_wal/目录中记录数据库变更,并在在需要时通过wal文件恢复到数据库指定状态的能力。 基于PITR机制,Postgres社区设计出来HA、Clone、备份、快照等等功能。

通常WAL文件按照segment分隔(默认大小为16MB)并以16进制的字符串命名(比如00000001000000000000002A)。

PG通过重命名的方式轮转使用WAL文件,用户可以archive_command配置收集产生的指定WAL,配置如下:

1
2
3
4
5
6
7
wal_level = 'replica'     # 至少为replica
archive_mode = 'on'       # 开启WAL文件归档
archive_timeout = '1800s' # 强制生成Wal的最短时间,太小的值会使WAL文件膨胀
wal_compression = 'on'    # 开启WAL压缩,PS:重放是自动解压
wal_keep_size = '128MB'   # 指定在pg_wal目录下保留的最小WAL大小,改配置主要是为了Standby服务器从Master中获取WAL文件
wal_log_hints = 'on'      # 请配置为ON
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'

设置archive_command='/bin/true',这种配置实际上禁用了归档功能,目的是为了可以在不重启Postgresql的前提下随时替换archive_command的值从而开启归档功能。

设置archive_command='',这种配置实际上暂停了归档功能,wal文件会保留在pg_wal目录中,直到archive_command配置恢复

wal_keep_size指的是最小值

wal_level可选值为 minimal、replica、logical,其中minimal不支持从wal恢复数据库

archive_command 返回非0值时,会导致Postgresql持续重试,pg_wal的目录不断增大,当pg_wal空间不足时会导致PostgreSQL不可用。同时archive_command的执行速度应当能够保证避免wal文件堆积。 归档时最好手动备份postgresql.conf,pg_hba.conf,pg_ident.conf

命令行工具pg_switch_wal可以手动立即生成wal存档

当存在一个已经运行的PostgreSQL实例时,假设用户需要为该实例创建全量备份,由于用户之前没有开启WAL归档,因此需要首先生成Base Backup。

生成Base Backup可以通过pg_basebackup工具(参考) 或者直接调用SQL([参考](https://www.postgresql.org/docs/11/continuous-archiving.html#BACKUP-LOWLEVEL-BASE-BACKUP))。

Base Backup生成一个完整的数据库拷贝,当PostgreSQL的数据目录完全不可用时,用户可以解压Base Backup文件,基于该备份和归档的archive wal来恢复数据(参考)。

关于recovery.config文件的配置可以参考官方文档

Timelines

为了避免反复恢复到WAL的不同时间点,造成的WAl内容混乱,Postgres引入了“时间线”的概念。每次PostgreSQL恢复WAL完成时,新生成的WAL文件会用不同的文件名前缀表示Timelines ID, 即在不同wal文件中,会出现相同id的wal记录。 用户在恢复备份时可以在recover.conf文件中指定Timelines ID,从而恢复到不同时间线上的数据库状态

参考:https://www.postgresql.org/docs/11/continuous-archiving.html#BACKUP-TIMELINES

PITR For HA

HA场景中多个PostgreSQL实例组成HA集群,其中一台作为Master运行,其余作为Standby运行。Master运行在WAL Archiving状态,Standby运行在Recovery状态。Standby通过WAL文件或者WAL数据流持续从Master同步数据库的修改。

HA方案基于Wal复制时,具备以下特性:

  • 无需修改表结构
  • 基于较低层级实现同步(相比基于触发器、SQL复制等方案),对Master的性能影响很小
  • 异步复制(WAL记录在事务提交后传送),可能丢失最近一个时间窗口的数据
  • 跨大版本的Postgresql实例无法实现复制,官方建议Master和Standby的版本应该一致
  • 如果在Master上执行CREATE TABLESPACE,则必须所有Standby节点上相同的路径是可访问的

基于Streaming Replicas时,Master可以关闭Wal Archiving!

Standby Server

Standby始终运行在Recovery模式中,该模式下Standby从以下三个位置获取WAL:

  • restore_command(参考)的配置
  • pg_wal目录
  • streaming replication

Standby顺序从上述位置读取WAL文件,任意位置读取完毕或者退出都会读取下一个位置,不断循环!

Standby Server的配置如下:

1
2
3
4
5
6
7
8
# recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=standby passfile=/run/postgresql/pgpass host=99.233.166.135 port=5432 sslmode=prefer application_name=minimal-cluster-1'
primary_slot_name = 'minimal-cluster-1'
recovery_target_timeline = 'latest'                                    # 表示保持Recovery状态
restore_command = 'cp /path/to/archive/%f %p'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'      # 清理不再有用的WAL文件
trigger_file = '/path/to/archive/stop_standby'                         # 当该文件存在时离开standby模式

注意:PostgreSQL 12开始recovery.conf配置整合到postgresql.conf中。如果数据文件目录中存在recovery.conf文件,数据库将无法启动。

注意:PostgreSQL 12 standby_mode参数不再支持,用户通过在数据库目录中创建standby.signal文件来触发Standby模式

在8.4以及之前的版本,PostgreSQL并没有提供完善的standby运行模式,用户需要借助restore_command配置专门设计的脚本,实现特定主机(Standby)处于一个死循环中,并不断的获取Master的WAL文件。 官方提供了一个pg_standby工具简化这些配置。

8.4以及之前版本的Standby模式,参考:https://www.postgresql.org/docs/11/log-shipping-alternative.html

上述配置中,recovery.conf同时配置了从文件和Streaming恢复数据。根据场景也可以省略restore_command和archive_cleanup_command,使Standby只从Master的tcp流同步数据。

Streaming Replication

相比于基于WAL Replication方案,PostgreSQL支持基于Streaming Replication的流式复制,Streaming Replication相比于基于文件同步,极大了缩小可能丢失数据的时间窗,可以不修改archive_timeout的情况下实现秒级甚至更小的延迟。

当Standby长时间下线,并且Master仍在提供读写服务时,为了避免Master服务删除WAL文件,可以有下面解决方案:

  • 用户可以设置wal_keep_segments确保Master保持足够大小的WAL文件,保证Standby上线后能够正常追赶上Master。

  • 开启Master的WAL归档功能,Standby上线后优先从WAL文件中恢复!

  • Replication Slots

当备用数据库启动并且 primary_conninfo 设置正确时,Master/Standby建立连接成功时,Postgres会在Master和Standby上各自启动线程执行Streaming Replication:

上图中Master上运行了两个walsender进程,表示此时有2个Standby从该服务复制数据。PS:Standby上的对应进程名称为walreceiver!

PostgreSQL使用Streaming Replication时支持级联,Standby可以在接收上游WAL的同时作为下游Standby同步WAL数据的源头。通过级联的方式可以减轻Master服务的负担以及减小带宽。

参考:https://www.postgresql.org/docs/11/warm-standby.html#CASCADING-REPLICATION

Replication Slots

为了保证Standby下线后,Master不会删除主机需要WAL文件,Postgres在9.4版本中引入的Replication Slots功能,主要包括:“物理复制槽”和“逻辑复制槽”,后者主要使用在Logical Streaming Replication场景。

使用Replication Slots时,Master节点需要在数据库中创建相应名称的复制槽,Standby在启动时通过primary_slot_name指定自己使用的复制槽。

1
2
3
4
5
6
7

-- 查看replication_slots状态
select * from pg_replication_slots ;
-- 创建replication_slots
select * from pg_create_physical_replication_slot('test');
-- 删除replication_slots
select * from pg_drop_replication_slot('test');

删除replication_slots之前需要先将replication_slot设置为不活跃状态,即删除对应standby中的primary_slot_name配置并重启服务。

pg_replication_slots 表的格式不同PG版本略有不同

在开启Replication Slots时,Master通过接受Standby的应答来确认WAL的同步情况,用户可以通过wal_sender_timeout调整应答的超时时间。

由于Replication Slots机制可能造成WAL文件堆积,因此在支持keepalive套接字选项的系统上,设置 tcp_keepalives_idle、tcp_keepalives_interval 和 tcp_keepalives_count及时发现Standby断开连接。PS:Unix系统不支持该配置

Authentication

由于Standby需要连接Master,因此配置Standby集群时需要在Master主机创建具有REPLICATION和LOGIN权限的账户,pg_hba.conf可以如下配置:

1
2
3
# 允许standby用户在本地套接字登录或者基于SSL登录,replication表示streaming Replication连接,不指代任何数据库
local   replication     standby                    trust
hostssl replication     standby all                md5

Synchronous Replication

通过修改Master服务的配置,用户实现Synchronous Streaming Replication。在该模式下Master写入事务的每次提交都会等待,直到收到确认提交已写入Master和Standby上。

Synchronous Replication的行为和安全级别和以下两个参数有关,且这两个参数均。

synchronous_commit

synchronous_commit表示事务返回到Client时,是否要等待WAL记录被写入磁盘,当前支持的类型包括:

参数 Master Standby 备注
off 无需等待 无需等待
local 写入文件 无需等待
remote_write 写入文件 写入Buffer
on 写入文件 写入文件 默认值
remote_apply 写入文件 写入文件且重放

synchronous_commit的配置可以为整个系统指定,但也可以为特定用户或连接,甚至单个事务指定。

synchronous_standby_names

默认情况synchronous_standby_names配置为空,表示Master上没有配置同步Standby。如果用户需要开启同步Standby,可以按照以下进行配置:

假设Master包含Standby:S1、S2、S3、S4

以下配置选择S1、S2、S3作为“备选同步standby”,且优先级S1 > S2 > S3,当S1、S2都在线时需要他们回复之后写入才返回Client,S1、S2任意下线后,S3升级为同步standby。

1
synchronous_standby_names = 'FIRST 2 (s1, s2, s3)'

以下配置表示S1、S2、S3,任意两个返回,即可返回Client。

1
synchronous_standby_names = 'ANY 2 (s1, s2, s3)'

需要注意:当standby刚刚开机时,对Master处于追赶状态,此时无法成为synchronous_standby,因此如果master上synchronous_commit的安全级别高于或者remote_write,那么可能出现Client无法写入的情况。

常用函数

主要参考官方文档系统函数列表中: Backup Control 、Recovery Control、Replication Control相关,此处不一一列举。

1
2
3
4
-- Master执行,用于判断同步进度
select * from pg_current_wal_lsn();
-- Standby执行,用于判断同步进度
select * from pg_last_wal_receive_lsn();

Failover

PostgreSQL提供了有限的机制,进行Master和Standby的切换,包括:

  • recovery.conf文件中的trigger_file配置:如果该配置指定的文件存在,那么pg立即退出standby模式
  • pg_ctl promote命令:该命令同样使pg退出standby模式
  • pg_rewind:用于将故障下线的Master重新和新Master同步数据,并作为新的Standby重新上线

PostgreSQL没有提供自动的主备切换工具,以及Master是否可用的监控工具,这一切需要第三方工具实现。

参考:https://www.postgresql.org/docs/11/warm-standby-failover.html

Hot Standby

Hot Standby指PostgreSQL实例具备以下能力

  • 处于recovery或standby状态时向外提供只读能力
  • 从recovery过度到正常状态时,用户的查询和连接不受影响

主机开启hot_standby=on的限制,参考:官方文档

参考