GBase 8c 逻辑复制槽停住以后,xlog 为什么越堆越多

GBase 8c 逻辑复制槽停住以后,xlog 为什么越堆越多

我最近看 GBase 8c 逻辑复制槽相关资料时,比较有感触的一点是:复制槽不是同步工具随手建出来的临时对象,它更像数据库端给下游消费方保留变更流的一份承诺。下游没有确认消费,数据库就要继续保留对应位置之后的 xlog;同步任务已经废弃但槽还留着,最后经常表现成"业务没什么大操作,磁盘却一直涨"。

这类问题在异构同步、准实时入仓、割接验证、双写过渡阶段都容易遇到。应用侧看到的是同步延迟,运维侧看到的是磁盘告警,数据库侧真正要看的往往是逻辑复制槽有没有推进。我自己理解下来,GBase 8c 的逻辑复制槽要当成日常巡检对象,而不是等 xlog 目录快满了才临时处理。

先看槽,不要先删文件

逻辑复制通过反解 xlog 生成逻辑变更流,下游按变更做同步。复制槽保存了消费位置,常见插件可以使用 wal2json。排查时我最关注下面几个字段:

字段 现场含义 我会怎么判断
slot_name 槽名称 是否能对应到同步链路台账
active 是否有客户端连接 长期为 false 要确认是否遗留
restart_lsn 槽需要的最早 xlog 位置 和当前 xlog 位置差距越大,保留压力越大
confirmed_flush 下游确认消费的位置 多次采样不变,说明消费没有推进
plugin 输出插件 是否符合链路设计,例如 wal2json
catalog_xmin 逻辑槽保留系统表变更边界 长期不动时要留意清理和版本影响

我不建议看到 xlog 目录大就先到系统层面删文件。对逻辑复制槽来说,数据库保留 xlog 是为了保证下游还能从断点继续消费,绕过数据库直接处理文件,很容易把问题从"空间风险"变成"同步断点丢失"。

参数设计不要只按当前一条链路算

逻辑复制槽使用前,至少要把几个参数和权限想清楚。真正落到现场时,很多问题不是函数不会用,而是槽数量、主备切换、安全访问这些边界没规划。

配置项 常见方向 落地提醒
wal_level logical 允许逻辑解析 xlog
enable_slot_log on 需要主备切换后保留槽信息时要重点验证
max_replication_slots 按物理槽、备份槽、逻辑槽合计预留 不要只给正式链路留名额,测试和割接槽也会占用
replication 访问规则 只放通同步服务网段 避免为了方便写过宽网段
同步账号 授予 REPLICATION 等必要权限 不建议直接拿业务高权限账号跑 CDC

示例配置可以这样检查:

sql 复制代码
show wal_level;
show enable_slot_log;
show max_replication_slots;

select slot_type, count(*)
from pg_replication_slots
group by slot_type;

示例环境里,我会把同步网段和账号单独管起来,下面地址只是占位写法:

bash 复制代码
gs_guc reload -Z coordinator -N all -I all -c "wal_level = logical"
gs_guc reload -Z coordinator -N all -I all -c "enable_slot_log = on"
gs_guc reload -Z coordinator -N all -I all \
  -h "host replication cdc_reader 10.18.40.0/24 sha256"

wal_level 这类参数是否需要重启,要结合实际版本和生效状态确认。我更倾向于在变更窗口处理,不在业务高峰临时修改。

创建槽以后马上纳入巡检

只要新增逻辑复制槽,我会同步补一条巡检 SQL。先看槽列表:

sql 复制代码
select
    slot_name,
    database,
    plugin,
    slot_type,
    active,
    restart_lsn,
    confirmed_flush,
    xmin,
    catalog_xmin
from pg_replication_slots
where slot_type = 'logical'
order by slot_name;

再估算当前 xlog 位置和 restart_lsn 之间的差距。这个数不完全等同于实际目录占用,但很适合看趋势:

sql 复制代码
select
    slot_name,
    database as datname,
    plugin,
    active,
    restart_lsn,
    confirmed_flush,
    pg_size_pretty(
        pg_xlog_location_diff(
            case
                when pg_is_in_recovery() then pg_last_xlog_receive_location()
                else pg_current_xlog_location()
            end,
            restart_lsn
        )
    ) as retained_xlog_estimate
from pg_replication_slots
where slot_type = 'logical'
order by active, slot_name;

我一般按下面几类状态拆开看:

状态 可能原因 处理倾向
active=true 且保留量稳定 下游正常消费 持续观察
active=false 且保留量很小 可能是计划暂停或低频任务 先确认任务计划
active=false 且保留量持续变大 槽停滞或遗留 联系同步侧确认是否恢复、推进或删除
active=true 但保留量持续变大 连接还在,但消费跟不上 查目标端写入、网络、错误队列和同步吞吐

这里我不会用"非活跃就告警"这么粗的规则。更实用的是组合判断:非活跃持续时间、xlog 保留增长速度、磁盘剩余空间、同步任务状态。

peek 和 get 的差别很容易坑到人

逻辑复制槽有两个动作很像:peek 是看变更但不推进,get 是取变更并推进。调试时用错,短期看不出问题,时间长了 xlog 就会被槽拖住。

动作 函数 是否推进槽 适合场景
预览变更 pg_logical_slot_peek_changes 调试输出格式、临时排查
消费变更 pg_logical_slot_get_changes 正式 CDC 消费
手动推进 pg_replication_slot_advance 明确跳过某段日志

示例:只查看数据,不推进槽。

sql 复制代码
select data
from pg_logical_slot_peek_changes(
    'slot_cdc_order_202605',
    null,
    null,
    'pretty-print',
    '1'
);

示例:消费数据并推进槽。

sql 复制代码
select data
from pg_logical_slot_get_changes(
    'slot_cdc_order_202605',
    null,
    1000,
    'pretty-print',
    '1'
);

遇到"同步程序能看到变更,但数据库日志目录还在涨"的情况,我会优先核对程序到底调用的是 peek_changes 还是 get_changes。自研脚本里这个问题并不少见。

停滞以后按顺序排,不要一上来 drop

复制槽停住后,drop slot 确实能释放保留压力,但也可能让下游断点直接丢失。我自己的处理顺序一般是:先确认归属,再确认是否还能消费,最后再决定推进还是删除。

sql 复制代码
select
    slot_name,
    database,
    plugin,
    active,
    restart_lsn,
    confirmed_flush
from pg_replication_slots
where slot_type = 'logical'
order by slot_name;

如果槽名能对应到正在运行的同步链路,先查同步任务。常见根因包括目标库写入慢、目标端约束冲突、网络抖动、错误队列堆积、同步程序只连着但没有真正消费。

如果确认是历史测试槽或废弃链路,再删除:

sql 复制代码
select pg_drop_replication_slot('slot_tmp_check_202604');

如果下游已经通过全量重刷、断点重置等方式确认旧变更不再需要,可以考虑推进槽。这个动作我会要求留下操作记录,因为它解决的是数据库端保留压力,不自动保证目标端数据完整。

sql 复制代码
select pg_replication_slot_advance('slot_cdc_order_202605', '0/7A3D920');

主备切换要把槽一起演练

enable_slot_log 的作用是控制逻辑复制槽主备同步特性。我的理解是,如果现场有高可用切换,又希望逻辑复制链路在切换后尽量连续,就不能只验证数据库主备能切过去,还要验证槽信息和消费断点。

场景 enable_slot_log=off enable_slot_log=on
主库创建逻辑槽 备库可能看不到槽 备库可以看到槽信息
主备切换后 新主可能缺少原槽,链路需要重建 新主保留槽信息,更利于恢复
运维验证点 切换后是否需要重新建槽 切换后消费端能否重新连接并推进

真正做 HA 演练时,我会在切换前后各查一次 pg_replication_slots,再让同步链路产生一小批可校验变更。只看数据库角色切换成功,不看逻辑复制槽,后面排同步问题会比较被动。

无主键表要提前识别

逻辑复制不只是 insert 能同步就行,update/delete 更容易踩坑。无主键表如果没有合适的记录级别,删除事件可能无法被正确捕获。我的做法是先扫参与同步的表,找出没有主键的对象:

sql 复制代码
select
    n.nspname as schema_name,
    c.relname as table_name,
    c.relreplident
from pg_catalog.pg_class c
join pg_catalog.pg_namespace n on n.oid = c.relnamespace
where c.relkind = 'r'
  and n.nspname not in ('pg_catalog', 'information_schema')
  and not exists (
      select 1
      from pg_catalog.pg_constraint con
      where con.conrelid = c.oid
        and con.contype = 'p'
  )
order by n.nspname, c.relname;

核心同步表,我更倾向于补主键。短期无法补主键的表,可以评估使用:

sql 复制代码
alter table ods.trade_order_ext replica identity full;

但这不是无成本动作。REPLICA IDENTITY FULL 会让旧行信息记录得更完整,对行宽大、更新删除频繁的表,xlog 量会明显增加。所以它适合兜底,不适合当成所有无主键表的默认处理。

处理方案怎么取舍

动作 适用情况 风险点
重启同步任务 槽还在,断点有效 目标端错误没修好会继续失败
修复目标端写入 连接存在但消费变慢 排查期间 xlog 继续增长
pg_replication_slot_advance 下游确认可跳过旧日志 可能造成目标端缺变更
pg_drop_replication_slot 槽确认废弃 原断点丢失
临时扩容磁盘 保留量增长快且排查需要时间 只能止血,不能替代根因处理

从落地角度看,GBase 8c 逻辑复制槽要和同步链路台账、HA 演练、xlog 空间监控一起管。创建槽、消费槽、推进槽、删除槽,每一步最好都能对应到明确的业务目的。这样遇到 xlog 堆积时,排查路径会清楚很多:先看槽,再看消费,再看主备,再看无主键表,而不是只盯着磁盘目录做清理。

参考资料

text 复制代码
南大通用GBase 8c逻辑复制槽实践解析
https://www.gbase.cn/community/post/7148

南大通用GBase 8c逻辑复制槽功能实践示例
https://www.gbase.cn/community/post/5625

GBase8c使用wal2json逻辑复制槽
https://www.gbase.cn/community/post/4065

"G"术时刻 | GBase数据库逻辑复制槽功能应用实践
https://www.gbase.cn/news/3730

配置 Gbase 8c 数据节点 | DataPipeline 用户操作指南
https://docs.datapipeline.com/v4.4/rf6qi9891doe44zv/dzdm28q2vhtxgmic/fqszhng5l9m8gqyg/wr47yqspdsd6l1m7/gv5o6elrg1v2lpv7/
相关推荐
2401_880071401 小时前
html怎么用jekyll转换_Jekyll博客如何导入传统HTML页面
jvm·数据库·python
tellmewhoisi1 小时前
多版本共用redis导致数据没及时更新报错
数据库·redis·缓存
taocarts_bidfans1 小时前
Taoify与Redis、Nginx集成实战:提升跨境独立站性能与并发能力
数据库·redis·nginx·跨境电商·独立站
wang3zc2 小时前
CSS如何实现元素镜像翻转_使用transformscalex负值
jvm·数据库·python
CLX05052 小时前
Golang如何做图片处理缩放_Golang图片处理教程【收藏】
jvm·数据库·python
MongoDB 数据平台2 小时前
官宣:MongoDB 正式内置到 Claude Code
数据库·mongodb
TEC_INO2 小时前
Linux57:读取人脸数据库并保存到map
数据库·oracle
原来是猿2 小时前
TCP Echo Server 深度解析:从单进程到线程池的演进之路(下)
linux·服务器·数据库
2301_812539672 小时前
mysql如何限制用户连接数_使用MAX_USER_CONNECTIONS优化并发
jvm·数据库·python