自动提交的语义问题
开启自动提交后,消费者在后台按固定周期把「最近一次 poll 返回的位移」提交上去,提交的时机与业务是否处理完成没有关系。默认配置是开启、每 5 秒提交一次,所以进程如果处理到一半崩溃,已经提交的那一段位移不会再被消费,这部分数据就被跳过了。管道类消费几乎都应该关掉自动提交,改成处理成功后再手动提交。
基本信息
| 默认值 | enable.auto.commit=true,auto.commit.interval.ms=5000 |
|---|---|
| 提交内容 | 最近一次 poll 返回的位移,与处理进度无关 |
| 主要风险 | 未处理完的位移已提交,故障后跳过数据 |
| 建议配置 | 管道类消费关闭自动提交,改为处理后手动提交 |
| 提交方式 | commitSync 同步、commitAsync 异步 |
| 关联参数 | max.poll.records 决定单批处理时长 |
关闭自动提交
关闭自动提交
enable.auto.commit=false
max.poll.records=500 # 控制单批条数,缩短一轮处理时间
max.poll.interval.ms=300000 # 超过该间隔未 poll 会被踢出组
# 处理完成后按批提交(Java)
# 处理成功 -> consumer.commitSync();
# 处理失败 -> 不提交,下一轮重放该批典型使用场景
- 数据入仓管道:不能接受任何一条记录被静默跳过,必须关闭自动提交
- 事件驱动业务:业务处理成功才提交,失败时让消息重放
- 监控告警链路:丢一条告警比重复一条严重,语义选择要显式确认
- 高吞吐日志消费:可接受少量重复时,异步提交配合幂等下游更划算
- 排查「数据缺失」:先确认是不是自动提交导致位移提前推进
提交策略对照
| 策略 | 故障时表现 | 适用 |
|---|---|---|
| 自动提交 | 可能跳过未处理数据 | 允许丢失的粗粒度消费 |
| 处理完 commitSync | 可能重复处理一批 | 需要至少一次的管道 |
| 处理完 commitAsync | 吞吐高,失败不易感知 | 重复可被下游去重时 |
| 按分区提交 | 粒度更细,恢复更精确 | 分区处理耗时差异大时 |
| 提交前置(先提交再处理) | 可能丢数据 | 近似统计等场景 |
自动提交看似省事,但在「先提交后处理」的语义下,进程崩溃会直接造成数据空洞。
手动提交要配合下游幂等:至少一次语义下重放不可避免,下游按主键覆盖写或 upsert 才能保证最终结果正确。