PostgreSQL 19: 按需动态启用逻辑解码

John Doe 三月 17, 2026

长期以来,PostgreSQL 逻辑复制、逻辑解码(CDC)的使用一直存在重要痛点:必须在数据库启动前将wal_level设置为logical并重启实例,这意味着即便没有任何逻辑复制任务运行,数据库也要持续承担 logical 级别 WAL 日志带来的额外 IO、存储开销。

image

特性提交日志

根据逻辑复制槽是否存在,动态启用和禁用逻辑解码功能。

此前,逻辑解码需要在服务器启动时就将wal_level设置为logical。这意味着,即便没有使用任何逻辑复制槽,用户也必须承担逻辑级别 WAL 日志带来的开销。

本次提交新增了一项功能:根据逻辑复制槽是否存在,自动控制逻辑解码的可用性。新引入的模块logicalctl.c支持在wal_level设为replica时,按需动态开启逻辑解码。

当创建第一个逻辑复制槽时,系统会自动将有效 WAL 级别提升,以维护逻辑级别的 WAL 记录。反之,当最后一个逻辑槽被删除或失效后,WAL 级别会降回replica

激活操作会在创建第一个逻辑槽后同步执行,而停用则通过检查点进程异步完成。这一设计避免了在恢复结束时出现竞态条件:启动进程在恢复结束时启用逻辑解码的同时,可能并发触发停用操作,但在恢复完全完成前仍不允许 WAL 写入。

检查点会在恢复结束后处理此事。异步停用还能避免在频繁创建、删除单个逻辑槽的负载下,逻辑解码状态被频繁切换。不过,这种惰性机制可能会延迟effective_wal_level的变更以及逻辑解码的关闭,尤其在检查点进程繁忙时。我们在所有停用路径中都采用了这种惰性方案,以保持实现简洁,尽管严格来说只有恢复结束场景才必须如此。未来可通过改用专门的工作进程替代检查点,或在删除复制槽时实现同步等待,来解决这一限制 —— 如果负载受逻辑解码惰性停用显著影响的话。

内部由XLogLogicalInfo决定的有效 WAL 级别,允许在事务内、尚未分配 XID 之前发生变更。一旦分配 XID,该值在事务剩余生命周期内将保持固定。这一行为确保写入事务内的日志模式保持一致,与 GUC 参数的行为类似。

新增一个只读 GUC 参数effective_wal_level,用于监控当前实际生效的 WAL 级别。该参数反映当前运行时的 WAL 级别,可能与配置的wal_level不同。

讨论:https://postgr.es/m/CAD21AoCVLeLYq09pQPaWs+Jwdni5FuJ8v2jgq-u9_uFbcp6UbA@mail.gmail.com

特性示例

逻辑复制要求预写式日志(WAL)包含逻辑解码所需的信息。默认的wal_level配置值(replica)并不包含此类信息,而修改 WAL 级别需要重启服务器。

本补丁实现了系统根据逻辑复制槽是否存在动态判定 WAL 级别:创建第一个复制槽时,有效 WAL 级别会自动提升至logical;反之,当最后一个复制槽被删除后,有效级别会回落至replica。你可以通过新增的只读参数effective_wal_level查看当前实际生效的 WAL 级别。

\dconfig+ *wal_level
                     List of configuration parameters
      Parameter      |  Value  | Type |  Context   |  Access privileges   
---------------------+---------+------+------------+----------------------
 effective_wal_level | replica | enum | internal   | 
 wal_level           | replica | enum | postmaster | postgres=sA/postgres+
                     |         |      |            | alice=sA/postgres
(2 rows)

创建逻辑复制槽会触发有效 WAL 级别提升:

SELECT pg_create_logical_replication_slot('slot', 'pgoutput');
 pg_create_logical_replication_slot 
------------------------------------
 (slot,2/4BB9C340)
(1 row)

\dconfig *wal_level
List of configuration parameters
      Parameter      |  Value  
---------------------+---------
 effective_wal_level | logical
 wal_level           | replica
(2 rows)

删除唯一的复制槽后,下一次检查点(checkpoint)会将有效 WAL 级别降低:

SELECT pg_drop_replication_slot('slot');
CHECKPOINT;

\dconfig *wal_level
List of configuration parameters
      Parameter      |  Value  
---------------------+---------
 effective_wal_level | replica
 wal_level           | replica
(2 rows)

非常不错的体验,感谢所有参与的社区人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/67c20979ce72b8c236622e5603f9775968ff501c