1、消费者和消费者群组
(1)消息模型:队列模型(queuing) 发布-订阅模型(publish-subscribe)。
(2)Kafka两种模型提供单一消费者模型: 消费者组。 消费者用组名标记自己。Topic上消息发给此组中一个消费者。 1)所有消费者在一个组中,变成队列。 2)不同的组中,变成发布-订阅。
消费者(一个组)订同一Topic,每个接受一部分分区消息,实现扩展分流。场景:单个消费者无法跟上数据生成的速度
多个应用程序从同Topic读取所有的消息,保证有自己的消费者组即可,都能获取Topic全部消息;
2、Partition Rebalance分区再均衡
三种现象使partition所有权在消费者间转移,这样行为叫再均衡。
(1)消费者组中添加消费者读取到原本是,其他消费者读取的消息
(2)消费者关闭或崩溃后离开群组,他读取的partition组里其他消费者读(3)向Topic添加新的partition,partition在消费者中重新分配
优点:消费者组高可用性和伸缩性
缺点:1)期间消费者无法读取消息,有小段不可用 2)partition被重新分配给一个消费者时,消费者当前的读取状态会丢失,有可能还需要去刷新缓存,在它重新恢复状态之前会拖慢应用程序。
另:新版心跳变化(消费者向broker发心跳):1)独立心跳线程,轮询msg空档发心跳。2)指定不发心跳时间,避免活锁。
3、创建Kafka消费者、订阅主题、轮询
4、消费者的配置
1:fetch.min.bytes,消费者从broker获取消息的最小字节数,足够才返回
2:fetch.max.wait.ms,等待broker返回最大时间,默认500ms。和上面哪个先满足,就按哪种
3:max.partition.fetch.bytes,broker从每个partition中返回最大字节数,默认1MB
4:session.timeout.ms,死亡之前与服务器断开连接时间,默认3s
5:auto.offset.reset,读没有偏移量或者无效(消费者长时间失效,偏移量过时被删除)该作何处理。默认latest(消费者从最新读)。另一个earliest
6:enable.auto.commit,是否自动提交偏移量,默认true
7:partition.assignment.strategy,partition如何分配给消费者,默认Range:把Topic的若干个连续partition分配给消费者。RoundRobin:Topic所有partition逐个分配给消费者
8:max.poll.records,poll方法返回消息数
5、提交和偏移量
再均衡后,读partition最后偏移量,从指定地方处理。
(1)提交可能带来问题:小于客户端处理最后偏移量,两个偏移量之间消息重复处理;大于丢失
(2)提交方式:
1)自动提交:默认为true 5s
2)false:broker在对提交请求,回应前一直阻塞,限制吞吐量
3)异步提交:commitAsync后不重试,问题:提交偏移量2000,短暂通信问题,处理另外一批提交3000,。重新提交2000,这时候如再均衡,出现重复消息
4)同、异步组合提交:消费者关闭前用
6、再均衡监听器
平衡前,消费者知道即将不负责某分区,提交已处理过消息位移。调用subscribe()传ConsumerRebalanceListener对象有两个方法:
onPartitionRevoked(Collection partitions):停止消费后,重平衡前调用。
onPartitionAssigned(Collection partitions):读取消息前用。
7、从指定位移开始消费
分区开始/末端:seekToBeginning(TopicPartition tp) seekToEnd(TopicPartition tp)。
支持从指定位移开始消费:场景:位移存在其他系统(如数据库)中,并以db位移为准:保存db成功,提交位移到Kafka失败,消息会重复处理。不能优化方案为原子性操作,因此保存到数据库同时,保存位移,seek()来指定分区位移
8、优雅退出
退出poll循环时,用另一个线程调用consumer.wakeup(),poll()抛出WakeupException。
如wakup时,正在处理消息,那么poll时会抛出异常。解决:抛出WakeUpException后,调用consumer.close(),提交位移,同时发送退出消息到Kafka组协调者,重平衡
9、用Avro反序列化