消费者每次调用poll()方法,它总是返回由生产者写入Kafka但没有被消费者读取过的记录,我们因此可以知道哪些消息是被群组里的哪个消费者读取的。Kafka不会像JMS队列那样需要得到消费者的确认,消费者使用broker里的MetaData来追踪消息在分区里的位置(offset)。
更新分区当前位置的操作叫提交。
消费者会向_consumer_offset的特殊主题发送消息,消息里包含每个分区的offset。如果消费者一直处于运行状态,offset就没什么用处。如果消费者发生崩溃或者有新的消费者加入群组,就会触发再均衡,完成再均衡后,消费者可能会得到新的分区,而不是原来处理的哪个分区。为了能继续之前的工作,消费者需要读取每个分区最后一次提交的offset,然后从这个offset指定的地方继续处理。
提交操作会导致消息重复消费或者丢失。
如果提交的offset小于客户端处理的最后一个消息的offset,那么处于两个偏移量之间的消息就会被重复处理。例如,消费者A向分区1提交offset,这时发送了再均衡,分区1被分配给消费者B,由于网路原因,A提交的offset还没有到达broker,那么由于offset未更新,被A消费的消息就会被B重复消费。可以维护一个提交的自增版本号,如果这个版本号与提交的版本号一样,那么更新offset,否则,拒绝更新offset。
如果提交的offset大于客户端的最后一个消息的偏移量,那么处于两个偏移量之间的消息将会丢失。消费者A消费了分区0的一批消息,消息还在内存中处理,到了自动提交时间,提交了offset,但是随后消费者挂了,就会导致这部分消息丢失。
提交方式:自动提交、提交当前偏移量、异步提交、同步异步组合提交、提交特定的偏移量。
自动提交:最简单的提交方式,但是可能导致重复消费消息。设置enable.auto.commit=true,提交的时间间隔由auto.commit.intrval.ms控制,默认是5s。自动提交是在poll()方法里进行的,消费者每次进行轮询时会检查是否提交该偏移量了,如果是,那么就会提交分区当前偏移量。
要确保发生再均衡之前提交偏移量。