由 John Doe 七月 30, 2026
通过拆解 PostgreSQL 逻辑复制的工作机制,可以让我们更从容地使用逻辑复制来完成我们的业务目标。
目录
核心观点与关键结论
本文将详细拆解 PostgreSQL 中逻辑复制的底层工作机制。我们将通过追踪一条 INSERT 语句从“发布端(Publisher)”写入到“订阅端(Subscriber)”接收的完整生命周期,来揭示数据在物理写入、逻辑解码以及订阅端应用过程中的 9 个关键阶段。
物理复制与逻辑复制的对比:
- 物理复制(Streaming/Physical Replication):仅同步底层的二进制数据块,不关心具体的表结构和列数据,只执行“块级别的覆盖”。
- 逻辑复制(Logical Replication):需要精准理解被修改的表、列名及其对应的值。因此,要求数据库的
wal_level参数必须设置为logical,以便在 WAL(预写式日志)中写入额外的元数据(如数据来源、表关系、以及即使在全页写入时也保留完整的元组数据)。
逻辑复制核心工作流
整条链路可清晰划分为三个阶段:物理路径(发布端写入)、逻辑路径(日志解码与分发)、订阅端应用。
阶段一:物理路径(发布端执行与持久化)

1. 执行器处理 (Executor & Heap Tuple)
- 数据库接收并解析
INSERT语句后,执行器会生成一个堆元组(Heap Tuple)。 - 该元组包含了表头信息(如记录事务生命周期的
xmin和xmax标记)以及具体的列数据结构。
2. 写入共享缓冲区 (Shared Buffer)
- 通过空闲空间映射(Free Space Map),系统在内存中(表对应的页/块上)为该元组寻找合适的存储空间并上锁。
- 数据被写入内存,此时数据暂不具备防宕机(Crash-safe)能力。
3. 写入预写式日志 (WAL on Disk)
- 为了保证数据的持久性,变更会被组装成 WAL 记录写入内存,并在事务执行
COMMIT时刷盘(Flush)到磁盘。 - 此时,这条
INSERT语句才算真正持久化完毕。
阶段二:逻辑路径(日志解码与重组)

4. WAL 发送器与资源管理器 (WAL Sender & Resource Manager)
- 当订阅端发起连接请求时,发布端会启动 WAL Sender 进程。
- 该进程持续读取 WAL 日志,识别出资源管理器(如
RM_heap)并触发逻辑解码程序。
5. 重组缓冲区 (Reorder Buffer) —— 核心机制
- 问题:由于数据库支持并发,WAL 中的事务变更是交织错乱的(例如事务A和事务B交替执行)。
- 解决:Reorder Buffer 负责根据事务 ID(Transaction ID)在内存中重新对 WAL 流进行分组和排序。
- 它会缓存这些变更,直到监测到事务边界(如提交或回滚)。确认提交后,按 LSN(日志序列号)顺序将各个子事务梳理出队。
6. 复制槽 (Replication Slots)
- 作为一种安全保证机制,复制槽确保发布端不会过早清理掉订阅端尚未消费的 WAL 日志段。
- 它通过追踪
restart_lsn和已确认落盘的confirmed_flush_lsn,保证数据不丢失。
7. 输出插件 (Output Plugin)
- 输出插件负责将梳理好的逻辑变更转换为下游可读的特定格式。
- 常见的插件有:
test_decoding(人类可读格式)、wal2json(JSON格式,常用于 CDC 数据管道),以及pgoutput(PostgreSQL 原生的逻辑复制协议,会发送 BEGIN、关系映射、具体的 INSERT/UPDATE 以及 COMMIT 消息)。
阶段三:订阅端接收

8. 网络传输 (Network)
- 输出插件将解码后的变更消息通过网络流向订阅端。
9. 订阅端应用 (Apply on Subscriber)
- 订阅端接收到逻辑数据流(包含表名、列名和数值),启动一个本地事务。
- 直接在本地表中执行对应的
INSERT变更并提交。 - 提交成功后,订阅端更新自身的复制源 LSN,并将其反馈给发布端,表示该数据已被成功消费。
核心挑战与优化建议
- 大事务/长事务的隐患:
由于 Reorder Buffer 默认需要等待事务最终
COMMIT才会将变更发送给下游,极大的事务会导致内存(work_mem)耗尽并溢写到磁盘,造成极高的 I/O 压力,同时还会阻碍复制槽对旧 WAL 日志的清理。 - 解决方案(Streaming 选项): PostgreSQL 的逻辑解码协议提供了流式传输(Streaming)功能选项。开启后,发布端无需等待长事务的最终提交或回滚指令,即可在运行过程中将变更流式推送到订阅端,极大地缓解了主库的内存压力和 I/O 瓶颈。