内容提要
Postgres逻辑复制中,订阅默认关闭流式传输,发布端解码大事务时会在pg_replslot目录生成大量溢出文件,磁盘占用随订阅数成倍增长。将streaming设为on或parallel,可把解码数据直接发送给订阅端,避免发布端磁盘膨胀。Postgres 18已默认parallel,但含TOAST数据时仍可能溢出。
延伸解读
发布端磁盘膨胀的根源
逻辑复制中,发布端的walsender进程需要解码WAL,并将未提交事务的变更暂存在reorderbuffer中。当单个事务的变更量超过logical_decoding_work_mem(默认64MB)时,超出部分会以spill文件形式写入pg_replslot/<slot>/目录。每个订阅对应一个独立的复制槽和walsender,因此同一事务会被多次解码和溢出,磁盘占用随订阅数成倍增长。
streaming参数如何改变行为
订阅的streaming参数控制发布端在解码过程中是否直接流式传输事务内容。默认off时,发布端必须等事务提交后才发送,期间溢出到磁盘;设为on或parallel后,发布端在解码过程中即可将变更发送给订阅端,避免本地磁盘膨胀。parallel模式还会将变更直接交给订阅端的并行应用worker,进一步减轻发布端负担。
Postgres 18的改进与遗留风险
Postgres 18将streaming默认值改为parallel,但并非完全消除溢出。当元组包含TOAST数据时,即使启用流式传输,发布端仍可能产生spill文件。例如,插入大量宽行数据时,spill_bytes可能仍高达136MB。因此,升级到18后仍需关注pg_stat_replication_slots中的spill_count和spill_bytes,不能完全依赖默认设置。
监控与调优建议
DBA应定期检查pg_subscription中的substream列,确认订阅是否启用了流式传输。对于Postgres 17及更早版本,可通过ALTER SUBSCRIPTION ... SET (streaming = parallel)动态开启,无需重启。同时,监控pg_stat_replication_slots中的spill_txns、spill_count和spill_bytes,以及pg_replslot目录大小,可及时发现异常。对于大事务频繁的场景,适当调高logical_decoding_work
Q&A
Postgres逻辑复制中,发布端的pg_replslot目录为什么会突然被大量文件占满?
因为订阅默认关闭流式传输(streaming=off),发布端在解码大事务时,如果事务大小超过logical_decoding_work_mem(默认64MB),解码数据就会以溢出文件(spill files)的形式写入pg_replslot/<slot>/目录,导致磁盘占用激增。
如何避免逻辑复制在发布端产生大量溢出文件?
将订阅的streaming参数设置为on或parallel,让发布端在解码过程中直接将数据流式发送给订阅端,而不是先写到本地磁盘。在Postgres 16及以上版本,可以使用ALTER SUBSCRIPTION ... SET (streaming = parallel)或(streaming = on)来修改。
Postgres 18对逻辑复制的流式传输默认设置做了什么改变?
Postgres 18将streaming的默认值从off改为parallel,这意味着新创建的订阅默认会使用并行流式传输,从而减少发布端的磁盘溢出。但需要注意,如果订阅是从旧版本升级而来,可能仍保留旧的默认值。
即使启用了流式传输,Postgres 18在什么情况下仍可能发生溢出?
当事务中包含TOAST数据(如宽的行外存储的大字段)时,即使启用了流式传输,Postgres 18仍可能发生溢出。例如,使用EXTERNAL存储策略的6400字节文本字段,在插入大量数据时,仍会看到spill_bytes非零。
如何查看当前订阅的streaming设置以及复制槽的溢出统计信息?
可以查询pg_subscription系统表,其中substream列表示streaming设置(f=off, t=on, p=parallel)。溢出统计信息可以通过pg_stat_replication_slots视图查看,包括spill_txns、spill_count、spill_bytes、stream_txns、stream_bytes等字段。
逻辑复制中,多个订阅对发布端磁盘使用有什么影响?
每个订阅在发布端对应一个独立的复制槽,每个槽都有自己的walsender进程和reorderbuffer。当发生溢出时,同一个事务会被每个槽分别解码并写入磁盘,导致磁盘占用随订阅数成倍增长。例如,三个订阅可能导致三倍的溢出文件。