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/
相关推荐
程序员阿鹏26 分钟前
如何实现MySQL分库分表?
数据结构·数据库·sql·mysql·缓存
风哥2号44 分钟前
数据库教程FGMT33‑MySQL主从复制项目实施与维护06(MySQL8.4/9.7 MGR组复制)
数据库·mysql
liangsheng_g1 小时前
Spring事务传播行为分派与挂起恢复源码实战
数据库·sql·spring
蓝速科技1 小时前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
风哥2号1 小时前
数据库教程FGMT29‑Linux平台MySQL5.7安装配置与管理入门
数据库
杨云龙UP2 小时前
MySQL Host is blocked because of many connection errors 导致 JDBC 连接失败排查与解决
linux·运维·网络·数据库·sql·mysql·登录失败
这个DBA有点耶3 小时前
数据库数据同步解决方案怎么选?6款主流工具横向对比与信创选型指南
数据库·架构·dba
刃神太酷啦4 小时前
Redis 核心进阶:哨兵、集群、缓存问题与分布式锁详解----《Hello Redis!》(6)
linux·c语言·数据库·c++·redis·分布式·缓存
小雷信息医学4 小时前
不会写复杂代码也能发 SCI?手把手教你用 InSpireR 交互系统一键提取、合并与导出临床科研宽表【第三章】
数据库
旺仔不是程序员4 小时前
复合索引最左前缀原则:PostgreSQL 的 WHERE 为什么必须命中第一列
数据库·后端·sql