Offset是Kafka中标识消息在分区(Partition)内唯一位置的偏移量,本质是一个单调递增的整数。每个消费者组(Consumer Group)在每个分区上维护一个Offset,用于记录该组对该分区的消费进度——消费者通过Offset定位下次拉取的消息,确保消息不丢失、不重复消费。
Kafka提供了多种Offset存储方案,核心差异在于可靠性、性能及运维复杂度:
__consumer_offsets):__consumer_offsets主题(该主题采用压缩策略,仅保留最新Offset,避免日志膨胀)。每个消费者组的Offset按组ID哈希分区,确保同一组的Offset集中存储。这种方式无需额外组件,支持高吞吐,且与Kafka生态深度集成。seek()方法手动指定Offset),增加了运维成本。/consumers/<group.id>/offsets/<topic-partition>路径下。但由于ZooKeeper的写入性能有限(不支持批量写),高并发场景下易成为瓶颈,新版本已不推荐使用。Offset提交的时机和方式直接影响消息的消费可靠性,主要分为自动提交和手动提交两类:
enable.auto.commit=true(默认开启)、auto.commit.interval.ms=5000(默认每5秒提交一次)。__consumer_offsets主题。手动提交分为同步和异步两种,需将enable.auto.commit设置为false以关闭自动提交:
commitSync()):commitSync()方法后,会阻塞线程直到Broker返回提交结果(成功或失败)。若提交失败,会自动重试(默认重试次数由retries参数控制)。
commitAsync()):commitAsync()方法后,不会阻塞线程,提交操作在后台异步完成。可通过回调函数(Callback)获取提交结果(如记录错误日志),但不会自动重试(避免重复提交)。
close())或Rebalance前使用同步提交确保最后一次Offset提交成功(如在finally块中调用commitSync())。这种方案兼顾了性能与可靠性,是生产环境的常用实践。当消费者请求的Offset不存在(如Offset已被删除,Kafka默认保留7天)或消费进度异常时,auto.offset.reset参数决定了Offset的初始化行为:
earliest:从分区的最早消息(log_start_offset)开始消费;latest:从分区的最新消息(当前生产者写入的最新Offset)开始消费;none:若消费者组有已提交的Offset,则从该Offset开始;若没有已提交的Offset,则抛出NoOffsetForPartitionException异常。enable.auto.commit=false),根据业务处理结果(如消息写入数据库成功)手动提交Offset,确保消息不丢失。auto.commit.interval.ms设置为小于业务处理时间的值(如业务处理耗时10秒,设置为5秒),减少重复消费的概率。kafka-consumer-groups.sh工具或Prometheus+Grafana监控消费者组的lag(消费滞后量),及时发现消费延迟问题。onPartitionsRevoked(Rebalance前)和onPartitionsAssigned(Rebalance后)回调,onPartitionsRevoked中同步提交当前Offset,确保Rebalance后从正确位置恢复消费。