首页/数据/数据工程与 ETL 速查/Canal client 拉取与位点确认
CDC 与同步53 条

Canal client 拉取与位点确认

Canal 客户端以批次为单位拉取并回执位点:getWithoutAck 拉取、业务处理成功后 ack 提交、处理失败 rollback 让位点回退。ack 时机决定消息语义——先处理再 ack 是至少一次投递,先 ack 后处理则可能丢消息;批大小与处理耗时决定吞吐和重投规模。

Canal client 拉取与位点确认

Canal 客户端以批次为单位拉取并回执位点:getWithoutAck 拉取但不提交位点,业务处理成功后用 ack(batchId) 提交,处理失败则 rollback 让位点回退、下一轮重新拉取。ack 的时机决定消息语义——先处理再 ack 是至少一次投递(可能重复),先 ack 再处理则可能丢消息。批大小影响吞吐与重投规模:批次越大吞吐越高,但失败时重投的数据量也越大,业务处理时间与超时设置要匹配。

基本信息

拉取方式getWithoutAck(batchSize, timeout, unit) 返回批次
确认方式ack(batchId) 提交位点,rollback(batchId) 回退重拉
投递语义先处理再 ack 为至少一次,需业务幂等
批大小影响吞吐与失败重投规模之间的权衡
空批次无数据时也要按约定处理批次标识

客户端消费骨架(Java API 方法名)

客户端消费骨架(Java API 方法名)
// 拉取批次:批大小 1000,等待超时 5 秒
Message message = connector.getWithoutAck(1000, 5L, TimeUnit.SECONDS);
long batchId = message.getId();

if (batchId == -1 || message.getEntries().isEmpty()) {
    // 空批次:按实际 SDK 约定处理,不要当成正常数据
} else {
    try {
        process(message.getEntries());  // 业务处理(必须幂等)
        connector.ack(batchId);         // 处理成功后再确认位点
    } catch (Exception e) {
        connector.rollback(batchId);    // 失败回滚,下轮重新拉取
    }
}

ack 时机与语义

顺序语义风险适用
先处理再 ack至少一次重复投递,需幂等推荐,多数业务场景
先 ack 再处理至多一次处理失败则数据静默丢失仅在不敏感数据上使用
不 ack 不 rollback位点不推进重复消费同一批不可长期如此
部分线程 ack位点错位已 ack 部分未处理禁止
位点以 ack 为准:不 ack 会重复消费同一批数据,长时间不 ack 还会造成位点滞后持续增大,需要与监控联动。
catch 里吞掉异常后照样 ack 是最危险的写法:任务全绿、位点正常推进,但数据静默丢失,往往在业务对账时才发现。
多线程处理同一批次但只在部分线程成功后 ack,会让位点与处理进度错位;要么单线程处理完再 ack,要么先汇总各子任务结果再确认。
业务侧要按主键做覆盖写入或先去重再写,把至少一次投递的重复挡在入库环节:依赖位点保证不重复在有切换与回滚的链路里并不现实。

易错点

  • catch 里吞异常后照样 ack,数据静默丢失且任务显示成功
  • 多线程处理同一批次但只在部分线程成功后 ack,位点与处理进度错位
  • 把空批次的批次标识也 ack 或处理错,位点推进逻辑出现异常
  • 业务处理慢于批次超时,反复 rollback 重投,吞吐持续下降

数据来源与参考

  • Canal 官方文档(Client API:getWithoutAck/ack/rollback)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌