kafka位移机制
broker维护消费者的消费位移信息,老的版本存储在zk上,新版本存储在内部的topic里。本质上,位移信息消费者自己维护也可以,但是如果消费者挂了或者重启,对于某一个分区的消费位移不就丢失了吗?所以,还是需要提交到broker端做持久化的。
提交方式分为自动和手动。
自动是默认的行为,当然可以通过配置覆盖关掉自动提交。自动提交是consumer以一个时间间隔周期性地提交offset,比如每隔5s提交一次。提交发生的时机是poll调用时,会将上一次消费的位移信息提交到broker。自动提交的弊端在于有时间间隔,可能导致重复消费。比如5s提交一次,运行到第3s时,consumer断电挂了或者重平衡了,那么这3s内消费的消息可能没有提交上去,新的consumer再消费这个分区时,就会重复消费。
为了避免间隔导致的重复消费,我们可以每消费一条消息就提交一次,也就是手动调用commitSync提交。这样当然是最稳的,但是手动commitSync提交是同步阻塞式的,一次不成功,会导致重试,会在一定程度上影响性能。kafka还提供了一个异步版本commitAsync,这个方法是异步提交,性能问题基本忽略,但是如果提交失败并不会重试。(为啥?因为异步提交,如果重试的话,很可能已经有新的提交了,此时异步提交是一个老的位移,会导致重复消费)。那咋整呢?一般会推荐sync+async结合的方式。

while(true){
poll()
consume()
async commit()
}
sync commit()


也就是while循环里异步提交,即使有一次失败了,没关系,后面的异步提交总会成功的。但是如果是退出了,那么必须来一次同步提交,确保退出前的位移可以被提交。