kafka默认是poll模式:即生产者往topic里生产数据,消费者去topic拉去数据来消费 。
心跳、session timeout、auto-commit-interval时间间隔的关系?
如果消费者方法执行完时间小于auto-commit-interval,那么在消费者执行完方法时会提前出发自动提交
4个分区,1个Consumer | 4个分区,2个Consumer |
![]() | ![]() |
4个分区,4个Consumer | 4个分区,5个Consumer |
![]() | ![]() |
1,当多个Consumer订阅同一个主题并属于同一个Consumer Groups时,该组中的每个Consumer 将从该主题中的不同分区中接收消息。
2,1个partition只能被同组的一个consumer消费
3,自动提交消费偏移量(在拉取消息,@KafkaListener方法执行完后就提交?)
4,手动提交偏移量(注意红色部分)
@KafkaListener(topics = {"xxx"}, groupId = "xxx") public void vinQueueListener(ConsumerRecord<?, String> record, Acknowledgment ack) { dosomething(); // 手动提交offset ack.acknowledge(); }
对应配置:
kafka: bootstrap-servers: 127.0.0.1:9092 consumer: auto-commit-interval: 1000 enable-auto-commit: false group-id: xxx key-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer listener: concurrency: 4 ack-mode: MANUAL_IMMEDIATE
5,对于未commit偏移量的消息,消费者会在rebalance(比如重启消费者服务)后重新从上一次 提交的offset+1出开始重新消费。 (自己验证的时候发现一个问题:比如,消息1未提交offset,消息2未提交offset,然后消息3提交了offset,消息4未提交offset,那么在重启消费者服务后,只会从消息4继续开始消费,消息1和2就会被丢弃,消费不到。针对消费失败的数据可以将其存在本地数据库用定时任务去重复消费)
6,重复消费
(1)未提交offset会导致重复消费。
(2)消费消息的时候抛出异常会导致重复消费(默认好想是10次?)。
(3)(自动提交情况下)当消费一条数据超过session-timeout(默认10秒)(比如debug、业务逻辑耗时等),此时消费者会断开与broker的连接,从消费组中离开,即使你设置了自动提交属性,产生的offset也没法提交给Kafka,所以会触发rebalance,导致重复消费。所以,如果想给能力一直超过10秒的话会进入死循环重复消费。
解决重复消费:
(1)生产的时候为每条消息设置唯一标识,消费端做一个去重表判断是否重复消费。
(2)针对上面第三点,增加session-timeout、减少从kafka里面批量取的数据量、消费者拿到数据后,应该异步去处理。
7,Kafka消息丢失的情况
(1)auto.commit.enable=true,消费端自动提交offersets设置为true,当消费者拉到消息之后,还没有处理完 commit interval 提交间隔就到了,提交了offersets。这时consummer又挂了,重启后,从下一个offersets开始消费,之前的消息丢失了。
(2)参考上面第5点
(3)网络异常,网络抖动
(4)内存磁盘异常
8,消息积压
(1)比如消费者服务挂了,生产者一直在生产就会导致很多消息积压
(2)消费者能力跟不上生产者能力