1. 流复制和逻辑复制的差异
- 逻辑复制和流复制最直观的不同是,逻辑复制支持表级别复制
- 区分点事原理不同
-
- 逻辑日志是在wal日志产生的数据库上,由逻辑解析模块对wal日志进行初步的解析,解析结果是ReorderBufferChange(理解为HeapTupleData),再由pgoutput plugin对中间结果进行过滤和消息化拼接,然后将其发送到订阅端,订阅端根据接受到的Heap TupleData重新对其执行insert、delete、udpate操作
- 流复制时将数据从walrecord拷贝到数据页,
- 逻辑复制时将数据重新执行一次insert、update或delete
2. 流复制
- 流复制面对未提交的事务,事务没有提交也会同步到备机,当主库进行提交和回滚的时候,也会同步进行提交和回滚。对大事务相对友好
- 流复制会导致备机也会产生大量死元祖,需要做vacuum
- 流复制时将wal日志中记录的内容按照确切的块地址逐字节的拷贝到备库,因此主备之间数据分布是一样的,意味着主备机器上,同一条记录的ctid是相同的
3. 流复制的实现原理
- 后端进程通过执行XLogInsert和XLogFlush函数,将wal数据写入并刷新到WAL段文件中
- walsender进程将写入wal段的wal数据发送给walreveiver进程
- 发送wal数据后,后端进程继续等待备用服务器的ACK响应。更准确的说,后端进行通过执行内部函数SyncRepWaitForLSN获得一个latch,并等待他被释放
- 备用服务器上的walreveiver将接受到的wal数据写入备用的wal段中,使用write系统调用,并向walsender返回一次ACK响应
- walreveiver使用如fsync等系统调用将wal数据刷新到wal段,向walsender返回另一个ACK响应,并通知启动进程关于wal数据的刷新
- startup进程回访已写入wal段的wal数据
- 当walsender收到walreveiver的ack响应时,释放后端进程的latch,然后后端进程的提交或中止操作将完成。latch释放的时机取决于参数synchronous_commit,如果设置为on,当收到步骤5的ACK时释放latch,如果设置为remote_wirte,则在收到步骤3的ACK时释放latch
ACK的包括内容
- 写入最新wal数据的lsn位置
- 刷新最新wal数据的lsn位置
- 在启动过程中回放最新wal数据的lsn位置
- 发送此响应的时间戳
过程分析
- 主库的进程进行写操作
- 产生WAL record
- walsender感知到新的wal,发送给备库
- 备库接受,写盘再回放
是否发送wal日志与主库事务的提交与否没有关系,但主库是否能提交取决于备库的wal日志写入位置,默认是on的话需要落盘,备库实时回放
注意点
- 流复制就是借助latch实现主从进程间的协作
- 流复制场景下,只读事务、子事务的提交以及事务回滚,无需等待备库的ACK