消费者消费提交偏移量
消费者是被组内的其中一个消费者所管理,包括心跳检测,与组协调器进行通信,然后组协调器负责将消费者的leader的消费偏移量提交到kafka内置的主题中,这个偏移量也是具体消费者提交给代理组长的。
旧版消费者将消费偏移量提交到 ZooKeeper consumers/ {topicName}/$ partitionld }节点中,而新版的kafka是定义初始化了50个主题,命名为_consumer_offset_0-50,根据一些规则,发布到不同的主题当中去。具体规则如下:
(Math.abs ({group . id) . hashCode () { offsets.topic.num.partitions)
kafak中的提交策略
分为自动提交和手动提交,自动提交就是交给kafka去管理,后台延时去提交。手工提交为自己在代码中去控制提交的时机和是否丢失消息。
手动提交的话需要将参数改为false
enable auto.commit = false;
当然提交后也分为同步提交和异步提交:
同步提交时消费者在消费任务后,消费者协调器通知到组协调器去同步提交偏移量,SyncOffsetRequest 请求,如果提交一直未响应,会一直阻塞,不会消费后续的消息。
异步提交commitASync(),不会阻塞消费者,后台去处理提交,发生异常可能会重复消费,需要做消息幂等性处理,这种提交方式效率高。
自动提交的间隔时间
当使用enable auto.commit =true时,需要配置auto.commit.interval ms,自动提交的间隔时间,也就是每次自动提交间隔多长时间提交一次。设计这个的目的是为了减少服务端的压力,如果用定时任务的话,会增加资源,耗费性能。根据设置的时间去比对上一次提交的时间,如果没有超过就不提交,超过就提交,并更新当前的消费偏移量,设置下一次的消费偏移量nextAuto CommitDeane;
kafka中的controller控制器
当器群创建后,会选举一个kafka节点作为leader,负责整个集群中的主题创建与删除、分区和副本的创建与删除,以及故障转移工作,当leader挂掉之后,会重新选举出来一个leader,称为整个集群中的leader。
初始化所有的节点都会向zookeeper中创建/controller节点目录,谁创建成功,谁就是leader。
消费组与消费者的协调器
在老版本中的kafka中,kafka高级消费者是强依赖与zookeeper中的,每次消费者启动和关闭都会和zookeeper中的节点进行关联更改状态,初始化消费者后,会创建对应的zk节点,/consumers/$ {group. id }/ids 。
新版的kafka在老版的消费做了一次升级,引入了消费者协调器,和消费组协调器。当然为什么要升级呢,老版的消费者会引发两个问题:
1、脑裂问题
消费者进行平衡操作时每个消费者都与 ZooKeeper 进行通信,以判断消费者或是代理变化情况,由于 ZooKeeper 本身的特性可能导致在同 时候各消费者所获取的状态不 致,这样就会导致 Kafka 运行在 个不正确状态之下,鉴于旧版高级消费者存在问题,新版消费者进行了重新设计,引入了协调器.
2、羊群效应
当许多消费者加入到了集群中或者停止工作(集群平衡,分区从新分配),都会给zookeeper造成不小的压力。消费者的增减都会操作同一路径的节点,有可能造成死锁。
消费者协调器
本身就是用来代理消费者的一些行为,以及管理消费者的状态。包括向消费者组提交自己消费的偏移量,以及发送心跳,消费者的运行状态。当新的消费者加入到组中,会向组协调器发送joingroup请求,同样离开也会发送离开对应的请求。同时, eader 消费者的消费者协调器还负执行分区的分配,当消费者协调器向组协调器请求加入消费组后,组协调器会为同 个组下的消费者选出 Leader ,成为 Leader 的消费者其 ConsumerCoordinator 收到的信息与其他消费者有所不同。当重新分区时,消费者协调器的leader会将分配结果发送给组协调器,由组协调器将分配结果下发给其他follow的消费者,这种处理方式,减少了服务端的压力,工作都是在客户端做了。
消费组协调器
负责管理组内的消费者的偏移量的提交,消费者协调器会提交给组协调器,由组协调器调用kafka 的KafkaApis 提交给kafka中的内部主题中。当然还有组内成员的管理,新加的消费者要发送请求加入组的请求,组协调器中写入该消费者的元数据信息,并返回,消费者就可以提交消费的偏移量。
1、消费者加入消费组
Partition副本选举Leader机制
controller感知到分区leader所在的broker挂了(controller监听了很多zk节点可以感知到broker存活),controller会从ISR列表(参数unclean.leader.election.enable=false的前提下)里挑第一个broker作为leader(第一个broker最先放进ISR列表,可能是同步数据最多的副本),如果参数unclean.leader.election.enable为true,代表在ISR列表里所有副本都挂了的时候可以在ISR列表以外的副本中选leader,这种设置,可以提高可用性,但是选出的新leader有可能数据少很多。
副本进入ISR列表有两个条件:
-
副本节点不能产生分区,必须能与zookeeper保持会话以及跟leader副本网络连通
-
副本能复制leader上的所有写操作,并且不能落后太多。(与leader副本同步滞后的副本,是由 replica.lag.time.max.ms 配置决定的,超过这个时间都没有跟leader同步过的一次的副本会被移出ISR列表)
kafka单节点内部结构图介绍:www.processon.com/view/link/6…