admin 管理员组文章数量: 1086019
PostgreSQL 9.1之前,主从复制传输以WAL日志文件为单位,主库写完一个WAL日志文件后才传送到备库,这种方式导致主备延迟特别大。
9.1引入了主备流复制,传输单位是WAL日志的record,备库不断从主库同步相应的数据,并apply每个WAL record,因此9.1能够做到同步复制。同时9.1提供了Hot Standby,备库在应用WAL record的同时能够提供只读服务,大大提升了用户体验。
一、 主备流复制架构
PG主备流复制的核心由三个进程组成:
- walsender:用于主库发送WAL日志记录至从库
- walreceiver:用于从库接收主库的WAL日志记录
- startup:用于从库apply日志
二、 流复制的启动
1. 启动过程
本节探讨流复制的启动顺序,以了解三个核心进程如何启动,以及它们之间如何建立连接
- (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)流复制开始工作
2. walsender状态
通过pg_stat_replication视图可以查看所有正在运行的walsender状态
SELECT application_name,state FROM pg_stat_replication;
application_name | state
------------------+-----------
standby1 | streaming
standby2 | streaming
pg_basebackup | backup
walsender进程可能的状态如下:
- start-up:上图(5)~(6)
- catch-up:上图(7)
- streaming:上图(8)
- backup:由于备份发送整个数据库集群的文件,比如pg_basebackup
3. 备节点长期停机再启动后,会发生什么?
9.4以前,如果备节点请求的wal段在主节点已被覆盖,那么备节点将无法追上主节点。这个问题没有什么好的解决方案,只能把wal_keep_segments参数增大,减少发生的可能性。
9.4开始,这个问题可以使用复制槽(replication slot)来预防——通过暂停walreceiver进程,将含有未发送wal段的pg_xlog保存在复制槽中。复制槽可提高wal数据发送灵活性性,主要用于逻辑复制。
三、 流复制过程
流复制包含两个方面:日志传输和数据同步。
- 流复制是基于日志传输的,主节点会在写入日志记录时,将WAL数据发送到已连接的备节点。
- 同步复制需要数据库同步,主节点与多个备节点通信,从而同步整个数据库集群。
为了更容易理解,本节描述了一主一备的情况,下一节介绍一主多备的情况
1. 主备间的通信
假设在备节点处于同步模式、hot_standby参数已禁用、wal_level为'archive',即主库配置以下参数:
synchronous_standby_names = 'standby1'
hot_standby = off
wal_level = archive
假设后台进程在自动提交模式下在主节点发出一条insert语句。后台进程启动事务、发出一条insert语句、然后立即提交事务。我们来探讨如何完成此次提交。
- (1)后台进程执行XLogInsert()和 XLogFlush()函数,将wal数据写入缓存并flush到wal段文件。
- (2)walsender将写入wal段文件的wal数据发送到walreceiver。
- (3)主节点发送wal数据后,后端进程继续等待来自备节点的ACK响应。更确切地说,后台进程执行内部函数SyncRepWaitForLSN()来获取latch,并等待释放它。
- (4)walreceiver通过write()函数将接收到的wal数据写入备节点的wal缓存,并且返回ACK响应给walsender。
- (5)walreceiver通过fsync()函数将wal数据全部flush到wal段文件,并且再返回一个ACK响应给walsengder,通知startup进程wal相关数据已更新。
- (6)starup进程应用已经写入wal段文件的wal数据。
- (7)walsender在接受到ACK响应后释放latch,然后后端进程完成commit或abort动作。latch释放的时间取决于参数synchronous_commit(详细参考下片):如果参数是on,则在步骤(5)接受ACK响应后释放latch;如果是remote_write,那么在步骤(4)接受ACK响应后就释放latch。
如果wal_level设置为hot_standby或logical,pg会根据commit或abort操作的记录,写入热备功能相关的wal记录
2. ACK响应内容
ACK响应将备节点内部信息发送主节点,包含以下4个项目:
- 已写入的最新WAL数据的LSN位置
- 已刷新的最新WAL数据的LSN位置
- startup进程最新应用的wal数据的LSN位置
- 发送此ACK的时间戳
walreceiver不仅在写入和刷新WAL数据的时候返回ACK响应,还定期发送备节点心跳(心跳发送间隔通过wal_receiver_status_interval设置,默认10秒)。因此,主节点始终掌握所有已连接备节点的状态。
通过以下查询可以看到所连接备库相关LSN的信息
SELECT application_name AS host,write_location AS write_LSN,flush_location AS flush_LSN,replay_location AS replay_LSN FROM pg_stat_replication;
host | write_lsn | flush_lsn | replay_lsn
----------+-----------+-----------+------------
standby1 | 0/5000280 | 0/5000280 | 0/5000280
standby2 | 0/5000280 | 0/5000280 | 0/5000280
3. 发生故障时的行为
本节描述同步模式下备节点故障时主节点的行为,以及该如何处理这种情况。
即使同步备节点故障,不能再返回ACK响应给主节点,主节点也会继续等待备库的ACK响应。因此,在主节点运行的事务会无法提交,后续的查询也无法执行。换句话说,主节点所有的操作都停止(流复制不支持由于超时自动降级为异步模式)。
有两种方法避免这种情况的发生:
- 提供多台备节点来提高系统的可用性
- 通过手动执行以下步骤从同步流复制转换到异步流复制
# 1.设置synchronous_standby_names为空串
synchronous_standby_names = ''
#2.执行reload命令重载配置文件
pg_ctl -D $PGDATA reload
以上操作对已经连接的客户端没有影响,主节点会继续处理所有连接的session的事物。
四、 管理多个备节点
1. 同步优先级与同步状态
主节点会为自己的所有备节点指定sync_priority(同步优先级)和sync_state(同步状态)。
同步优先级
sync_priority表示备节点在同步模式下的优先级。它是一个固定值,值越小优先级越高,0是个特殊值,表示异步模式。备节点优先级是个有序列表,按synchronous_standby_names中的顺序依次给出。
例如,以下配置中standy1和standy2的优先级分别是1和2。参数中未列出的备节点是异步模式,优先级为0。
synchronous_standby_names = 'standby1,standby2'
同步状态
sync_state表示备节点的状态,这个值由各备节点的运行状态及优先级而定,以下是可能的值:
- Sync:具有最高优先级的同步模式备节点状态
- Potential:同步模式下优先级>=2的备节点状态。如果Sync状态(最高优先级)的备节点故障,优先级第二高(优先级=2)的备节点会代替故障节点变为最高优先级。
- ASync:异步模式备节点的固定值,除非修改同步模式,否则它们的状态永远不会是sync和potential。
可以通过pg_stat_replication视图查看这两个值
SELECT application_name AS host,sync_priority,sync_state FROM pg_stat_replication;
host | sync_priority | sync_state
----------+---------------+------------
standby1 | 1 | sync
standby2 | 2 | potential
2. 主节点如何管理多个备节点
主节点仅等待Sync状态备节点的ACK响应,换句话说,主节点仅确保Sync状态备节点已写入并刷新wal数据。因此,在流复制中,只有Sync状态备节点与主节点是始终的同步的。
下图展示了Potential状态备库ACK响应早于Sync状态备库的情况:此时主库并不会完成当前事务的提交操作,而要继续等待Sync状态备库ACK响应。当收到Sync状态备库ACK响应时,主库后端进程才释放latch并完成事务提交。
这里standby1和standby2的sync_state分别是sync和potentail。
- 尽管主库已接收到Potential状态备库ACK响应,但主库的后端进程还是持续等待Sync状态备节点ACK响应
- 接收到Sync状态备节点ACK响应后,主库后端进程释放latch,完成当前的事物提交
相反,如果主库先接收到Sync状态备库ACK响应,它会立即完成当前事物提交,而不去确认potentail状态的备库是否已写入并刷新wal数据。
3. 备库发生故障时的行为
Potential或Async状态备节点故障
主节点会终止连接到故障备节点的walsender进程,并继续进行自己的事务处理。换句话说,主节点的事务处理不受这两类备节点故障的影响。
sync状态备节点故障
主节点终止连接到故障节点的walsender进程,Potential状态备节点顶替故障的备节点变为Sync状态(期间主库不可用),在替换完成后主库恢复事务处理。因此,备节点的故障检测(下节介绍)对提高流复制高可用至关重要。
五、 备节点的故障检测
流复制使用两种常见的故障检测程序,不需要任何特殊的硬件。
1. 备节点进程的故障检测
- 当检测到walsender与walreceiver的连接中断时,主节点立即判定备节点或walreceiver出现故障。
- 当底层网络函数由于未能成功读/写walreceiver套接字接口而返回错误时,主节点也会立即判定其失效。
2.硬件或者网络故障检测
如果walreceiver在wal_sender_timeout内(默认60s)没有返回任何结果,主节点会认为备节点出现故障。与上述故障对比,即使备节点由于硬件、网络等故障已无法返回任何响应,主库也需要最长wal_sender_timeout的时间来确认备节点故障。
根据故障类型,在故障和检测之间可能会有时间差,特别是如果在Sync状态备库中发生第2种故障,那么即使有多个Potential状态备节点正常工作,检测到Sync状态备库失效,主库仍然可能会有一段时间不可用。
在9.2及之前版本,wal_sender_timeout参数被称为replication_timeout。
六、 进程通信详细过程
1. walsender和walreceiver的流复制过程
2. walreceiver和startup进程
参考
《postgresql指南 内幕探索》
http://mysql.taobao/monthly/2015/10/04/
版权声明:本文标题:pg主从复制(一)——流复制机制 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1738259507a1952397.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论