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,要么先汇总各子任务结果再确认。
业务侧要按主键做覆盖写入或先去重再写,把至少一次投递的重复挡在入库环节:依赖位点保证不重复在有切换与回滚的链路里并不现实。