简介
MogDB是开源数据库openGuass的商业发行版本,采用原生的流复制方式进行数据同步。主要原理为通过物理复制的方式把主库的WAL日志传输到备库,备库接收到WAL日志后然后进行重放以达到数据同步的过程。

数据同步是对主库整个实例级别做的复制备份,一个主库可以对应一个或多个备库。复制模式可以支持同步复制和异步复制,备库也可以当作复制源进行级联复制。
数据同步机制
MogDB以流复制的方式把WAL日志文件传到备库,流复制传输的单位是wal record。WAL日志由一系列的WAL记录(wal record)构成,每一个 wal record分配一个序列号lsn(log sequence number),顺序递增。
主备数据同步的过程中,主要涉及以下三个线程:
- walsender线程 :负责向备库发送wal record
- walreceiver线程 :负责接收主库的wal record
- startup线程 :负责把wal日志文件apply为data数据
数据同步的复制模式分为同步复制和异步复制两种。下面以同步复制为例说明下数据同步的过程。
同步复制模式

在流复制开始前,startup线程首先从本地归档或wal日志存放目录寻找是否有可回放的日志;如果没有,备库开始建立流复制连接以从主库获取要回放的wal日志文件。
- 首先startup线程会向备库主进程发送信号,启动walreceiver线程。
- walreceiver向主库主进程发送请求启动walsender线程,随后walsender建立一条与walreceiver的TCP连接。
- 流复制建立连接后,客户端应用程序连接数据库开始向主库提交事务。
- walwriter线程把事务日志从缓存刷到磁盘。
- walsender线程读取wal日志文件逐个向备库发送wal record。
当然在开始流复制前,备库会向主库发送备库最新的record lsn,以确定需要从什么地方开始发送wal record。需要注意的是,由于存放wal segment的目录是有一定容量限制的,达到容量后就开始向后覆盖wal文件。为了防止备库需要的wal日志被主库覆盖掉,主库在流复制建立连接后会默认创建对应备库的物理复制槽,这样就可以保留主库没有发送到备库的wal日志。也可以通过开启归档来保留wal数据,避免wal日志在存放目录被覆盖掉。 - 备库的walreceiver线程接收来自主库的wal record,并用walrecwrite线程把这record刷到磁盘上形成wal文件。
- 备库wal落地成文件后,startup线程开始进行回放,首先startup通过从加载的pg_control文件获取redo point,读取wal日志文件获取最新的wal record开始进行apply。在回放时,可以采用多个线程并行apply 日志数据,这样可以大幅提高回放效率。
同步复制中客户端需要等待备库返回的ACK消息,根据wal日志在备库的执行结果分为以下几个级别:
- remote_receive :表示备库接收到了wal日志数据
- remote_write :表示备库接收wal日志并刷到磁盘
- remote_apply :表示备库接收wal日志并完成回放
- 根据synchronous_commit设置的不同级别,备库的wal日志执行到相应的结果后,walreceiver线程会向walsender发送响应的ACK消息。
- walsender给postgres(在opengauss中是backend worker线程)发送消息释放latch锁,事务提交成功。
- postgres反馈给客户端事务提交成功的消息。
异步复制模式

异步复制过程中,主库客户端不必等待备库的ACK消息,待主库WAL日志落盘后,postgres就可以直接向客户端返回提交成功。其他关于WAL日志的发送,接收以及回放处理过程和同步模式是一样的。
最大可用模式
异步复制显然有数据丢失的风险,考虑到数据为重,MogDB默认采用同步复制模式。但是同步复制在备库宕机或网络问题下容易造成主库写阻塞的情况,进而影响到业务的连续性。为此MogDB提供了一种最大可用模式(most_available_sync),在开启该模式下,如果主库遇到写阻塞,则同步模式会转换到异步模式,保证主库写正常进行。如果备库恢复正常,复制模式可以切回到同步模式。需要说明的是,最大可用模式与synchronous_commit提交级别是没有关系的,在同步模式下,只要遇到写阻塞,最大可用模式就会进行相应的同异步转换来保证业务的连续性。
MogDB和postgreSQL对比
MogDB在沿用PostgreSQL数据同步机制之外,本身对数据同步也做了不少改进,特别是在性能方面。
| MogDB | PostgreSQL | |
|---|---|---|
| 1 | 对流复制wal日志的处理上采用线程模型。 | 流复制采用进程模型处理。 |
| 2 | 增加最大可用模式,避免了同步复制下因备库问题导致主库写阻塞。 | 无最大可用模式。 |
| 3 | Wal 日志文件可实现预分配,避免了因日志写满再分配造成的性能抖动问题。 | Wal日志文件在写满一个segment时再分配下一个,容易造成因分配日志时造成的性能抖动。 |
| 4 | 支持并行回放,提高了备库上wal日志的回放效率。 | 备库只能单进程回放。 |
| 5 | 除了支持wal日志的数据同步外,还支持数据行存表时的数据页同步机制。 | 只支持wal日志的数据同步。 |
| 6 | 逻辑复制需要逻辑解码借助第三方工具实现。 | 有独立的逻辑复制功能。 |




