PostgreSQL同步复制实现逻辑分析
源码版本:pg 14.3
源文件:src/backend/replication/syncrep.c
原文地址:https://www.mytecdb.com/blogDetail.php?id=239
1、PG同步复制简介
同步复制是 pg 9.1 版本引入的新特性,事务提交必须等待事务对应的 lsn 在同步的备库接收到之后,才能提交成功。同步复制的实现逻辑主要集中在主节点,主节点记录了哪些备节点是同步节点,需要等待事务 lsn 在这些同步的备节点上接收、刷盘甚至应用完成。
pg 同步复制的几种模式:
#define SYNC_REP_NO_WAIT (-1) // 异步复制,不需等待备节点
#define SYNC_REP_WAIT_WRITE 0 // 同步复制,等待备节点写wal日志
#define SYNC_REP_WAIT_FLUSH 1 // 同步复制,等待备节点写wal日志并刷盘
#define SYNC_REP_WAIT_APPLY 2 // 同步复制,等待备节点写wal日志并应用
commit 类型的 wal record 提供 apply 反馈,其他类型只提供 write/flush 反馈。pg 的同步复制只在 commit 阶段才会等待,因为只有 commit 类型才会影响主备事务的一致性。
2、函数调用关系
主节点 backend 进程提交事务,其函数调用关系如下:
CommitTransaction()
RecordTransactionCommit()
SyncRepWaitForLSN(),等待某个 lsn 在备库操作完成。
WaitLatch()
从 SyncRepWaitForLSN() 函数的调用看,pg 的同步复制,只在 commit 阶段才会等待备库确认,其他非 commit 类型的 wal 同步,不需要等待备库确认。在 SyncRepWaitForLSN() 函数内调用 SyncRepQueueInsert() 把当前 backend 进程放入 WalSndCtl->SyncRepQueue 等待队列,休眠等待备节点接收到 wal 日志、刷盘或者应用。
wal sender 进程负责将 wal 日志发送给备节点,根据备节点返回的消息,来唤醒相关的 backend 等待进程,其函数调用关系如下: