基本介绍
PostgrepSQL在数据目录的子目录pg_xlog子目录中维护了一个WAL日志文件,可以把WAL日志备份到另外一台备份服务器,通过重做WAL日志的方式在备服务器上恢复数据(类似Oracle的redo日志)。
WAL日志复制到另外一台备份服务器可以有两种方式:
1、 WAL日志文件复制
此种方式是写完一个WAL日志后,才把WAL日志文件拷贝到备份数据库中。这样通常备份会落后主库一个WAL日志文件,当主数据库发生故障时,主数据库的WAL文件并没有填充完毕未传输(默认16MB)、或者时延等原因导致WAL文件没有传输完毕,会导致被数据库可能存在一定的数据丢失。此种方式是postgreSQL9.0前版本主要提供的WAL日志复制机制。
采用此方式的WAL复制,需要:
- 主数据库的wal_level配置为archive或以上。
- PostgreSQL 9.1之后提供了一个很方便的工具pg_basebackup,使用完成一次基础备份到备数据库。
- 后续产生WAL文件,可以通过archive_command参数调度命令传输至备机。
2、流复制(Streaming Replication)
流复制是PostgreSQL 9.0之后才提供的新的传递WAL日志的方法。通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。它的好处是只要主库一产生日志,就会马上传递到备库,同WAL日志文件相比有更低同步延迟。
同时PostgreSQL9.0之后提供了Hot Standby能力,备库在应用WAL record的同时也能够提供只读服务。
WAL流复制支持同步、异步方式:
- 异步流复制模式中,主库提交的事务不会等待备库接收WAL日志流并返回确认信息,因此异步流复制模式下主库与备库的数据版本上会存在一定的处理延迟,延迟的时间主要受主库压力、备库主机性能、网络带宽等影响,当正常情况下,主备的延迟通常在毫秒级的范围内,当主库宕机,这个延迟就主要受到故障发现与切换时间的影响而拉长,不过虽然如此,这些数据延迟的问题,可以从架构或相关自动化运维手段不断优化设置。
- 同步流复制模式中,要求主库把WAL日志写入磁盘,同时等待WAL日志记录复制到备库、并且WAL日志记录在任何一个备库写入磁盘后,才能向应用返回Commit结果。一旦所有备库故障,在主库的应用操作则会被挂起,所以此方式建议起码是1主2备。
主从原理
PG主备流复制的核心由三个进程组成:
- walsender:用于主库发送WAL日志记录至从库
- walreceiver:用于从库接收主库的WAL日志记录
- startup:用于从库apply日志
先简单了解一下基本流程
(1)启动主、备服务器
(2)备节点启动startup进程
(3)备节点启动walreceiver进程
(4)walreceiver进程向主节点发送连接请求,如果主库尚未启动,walreceiver会定期重发该请求
(5)当主节点收到连接请求时,将启动walsender进程,并建立walsender与walreceiver之间的TCP连接
(6)walreceiver发送备节点最新的LSN,这个阶段在IT领域称为握手机制
(7)如果备库最新LSN小于主库最新LSN(落后),walsender会将前一个LSN到后一个LSN之间的wal数据发送到walreceiver。这个阶段就是备库追赶主库的阶段。
(8)流复制开始工作
在详细了解一下流程
主要分为以下几个流程:
①主备数据库启动,备库启动startup进程,备库启动walreceiver进程,wal进程向主库发送连接请求。
②主库收到连接请求后启动walsender进程,并与walreceiver进程建立tcp连接。
③备库walreceiver进程发送最新的wal lsn给主库。
④主库进行lsn对比,定期向备库发送心跳信息来确认备库可用性,并且将没有传递的wal日志进行发送,同时调用SyncRepWaitForLSN()函数来获取锁存器,并且等待备库响应,锁存器的释放时机和主备同步模式的选择有关。
④备库调用操作系统write()函数将wal写入缓存,然后调用操作系统fsync()函数将wal刷新到磁盘,然后进行wal回放。同时备库向主库返回ack信息,ack信息中包含write_lsn、flush_lsn、replay_lsn,这些信息会发送给主库,用以告知主库当前wal日志在备库的应用位置及状态,相关位置信息可以通过pg_stat_replication视图查看。
⑤如果启用了hot_standby_feedback参数,备库会定期向主库发送xmin信息,用以保证主库不会vacuum掉备库需要的元组信息。
扩展问题
备节点长期停机再启动后,会发生什么?
-
9.4以前,如果备节点请求的wal段在主节点已被覆盖,那么备节点将无法追上主节点。这个问题没有什么好的解决方案,只能把wal_keep_segments参数增大,减少发生的可能性。
-
9.4开始,这个问题可以使用复制槽(replication slot)来预防——通过暂停walreceiver进程,将含有未发送wal段的pg_xlog保存在复制槽中。复制槽可提高wal数据发送灵活性性,主要用于逻辑复制。