openGauss源码解析(55)
openGauss源码解析:存储引擎源码解析(23)
主备日志同步,主要包括以下6个场景。
1. 备机发起复制请求,进入流式复制。
图4-38 主备建连和流式复制流程图
如图4-38所示,日志复制请求是由“wal receiver”线程发起的。在libpqrcv_connect函数中,备机通过libpq协议连上主机,通过特殊的连接串信息,触发主机侧启动“wal sender”线程来处理该连接请求(相比之下,对于普通客户端查询请求,主机启动backend线程或线程池线程来处理连接请求)。在WalSndHandshake函数中,wal sender线程与wal receiver线程完成身份、日志一致性等校验之后,进入WalSndLoop开始日志复制循环。主要的主、备机握手和校验报文如表4-34所示,在主机收到T_StartReplicationCmd报文之后,开始进入日志复制阶段。
表4-34 主、备机握手和校验报文
报文类型 | 报文作用 |
---|---|
T_IdentifySystemCmd | 请求主机发送主机侧system_identifier,校验是否和备机一致 |
T_IdentifyVersionCmd | 请求主机发送主机侧版本号,校验是否和备机一致 |
T_IdentifyModeCmd | 请求主机发送主机侧HA状态,校验是否是主机状态 |
T_IdentifyMaxLsnCmd | 请求主机发送当前最大的lsn位置(即日志偏移),用于备机重建 |
T_IdentifyConsistenceCmd | 请求主机发送指定lsn位置日志记录的crc值,校验是否和备机一致 |
T_IdentifyChannelCmd | 请求主机校验备机的端口是否在repliconn_info参数中,返回校验结果 |
T_IdentifyAZCmd | 请求主机发送主机侧AZ名字 |
T_BaseBackupCmd | 请求主机开始发起全量重建 |
T_CreateReplicationSlotCmd | 请求主机创建流复制槽 |
T_DropReplicationSlotCmd | 请求主机删除流复制槽 |
T_StartReplicationCmd | 请求主机开始日志复制 |
2. Quorum一致性复制协议
为了保证数据库数据的可靠和高可用,当主机上执行的事务修改产生日志之后,在事务提交之前需要将本事务产生的日志同步到多个备机上。openGauss采用Quorum一致性复制协议,即当多数备机完成上述事务的日志同步之后主机事务方可提交。这个过程中作为事务提交参考的是同步备,其他备机是异步备,作为冗余备份。同步备和异步备的具体选择可以通过配置synchronus_standby_names参数实现。
图4-39 事务提交和一致性复制协议
主机上事务提交和一致性复制协议的工作运行机制如图4-39所示。主要涉及的数据结构是WalSndCtlData数据结构体,其定义代码如下:
typedef struct WalSndCtlData {
SHM_QUEUE SyncRepQueue[NUM_SYNC_REP_WAIT_MODE];
XLogRecPtr lsn[NUM_SYNC_REP_WAIT_MODE];
bool sync_standbys_defined;
bool most_available_sync;
bool sync_master_standalone;
DemoteMode demotion;
slock_t mutex;
WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
} WalSndCtlData;
其中SyncRepQueue是等待不同同步方式(备机日志写入磁盘、备机日志接收、备机日志回放等同步方式)的业务线程等待队列,用于当某一种同步方式满足条件之后,唤醒该类型的业务线程完成事务提交。lsn是上述几种队列队头后台线程等待的日志同步位置。sync_standbys_defined表示是否配置了同步备机。most_available_sync表示是否配置了最大可用模式;如果已配置,则在没有同步备机连接的情况下,后台业务线程可以直接提交,不用阻塞等待。sync_master_standalone表示当前是否有同步备机连接。demotion表示主机的降备方式。mutex表示保护walsnds结构体并发访问的互斥锁。walsnds表示保存wal sender的具体同步状态和进度信息。
3. 计划外切换(failover)
图4-40 failover流程示意图
如图4-40所示,failover(故障切换)时主机是异常状态,所以只有备机参与failover。failover的核心是让备机在满足一定条件以后退出日志复制和日志恢复流程。当数据库主线程“postmaster”线程(简称PM线程)在reaper中收到“startup”线程(即恢复线程)的停止信号后,将实例状态设置为PM_RUN,并将实例HA状态设置为PRIMARY_MODE。
4. 计划内切换(switchover)
图4-41 switchover流程示意图
如图4-41所示,switchover的过程比failover多了主机降备的处理,备机的流程和failover流程一致,因此没有在图中标出,参考failover流程即可。
5. 备机重建
图4-42 备机重建流程示意图
如图4-42所示,备机重建的过程相当于对主机进行了一次全量备份和恢复的操作,主要步骤包括:清理残留数据、全量拷贝数据文件、复制增量日志、启动备实例。这个过程中比较关键的两点是:文件和日志的拷贝顺序,以及备机第一次启动时选择的日志恢复起始位置。
6. cstore数据复制
在openGauss中,对于cstore表的数据复制与上述介绍略有不同。在一主多备部署场景下,每个CU填充写盘之后都会将CU整体数据记录到日志文件中,从而通过主备的日志复制和备机的日志回放,就可以实现cstore表增量数据的主备同步。在主备从部署场景下,每个CU填充写盘之后会直接将该CU数据拷贝到主机与备机之间的数据发送线程的局部内存中,并在事务提交之前阻塞等待数据发送线程传输完增量的CU数据才能完成事务提交,因此也实现了cstore表增量数据的主备同步。