kafka是scala语言开发的,它时运行在jvm虚拟机上的,kafka天生就是集群,单个服务也是集群,横向拓展非常方便,修改少量配置即可。当然kafka依赖zookeeper搭建集群,在zookeeper中kafka创建的目录比较多,挑选几个重要目录分析kafka是如何依赖zookeeper工作的。
kafka中集群总控制器Controller选举
kafka在启动时会向zookeeper发起创建临时节点请求,节点名称为controller,只有第一个到达zookeeper的请求会成功创建controller的临时节点,这个broker就被选举为总控制器controller。
而集群其他broker会监听这个临时节点的变化,一旦总控制器controller宕机了,这个临时节点就会被删除,二塔broker监听到变化立马发起请求创建controller临时节点,创建成功的就会被选举为controller。
controller额外的职责
当某个分区的Leader副本挂了以后,它负责为该分区选举新的Leader副本
当检测到某个分区的Isr列表发生变化,有总控制器负责通知其他broker更新器元数据信息。
当使用kafka脚本为某个topic新增分区时,由总控制通知其他broker有新分区增加。
partition副本选举为leader机制
总控制器感知到某分区的Leader副本所在的broker挂了,它会从该分区的Isr列表中选择第一个brokerid作为Leader副本,因为他是第一个进入Isr列表的,她所同步的数据是最多的。当配置参数unclean.leader.election.enable为true,Isr列表为空时,会选择Isr列表以外的broker作为leader。
消费者消费消息的offset记录机制
消费者在消费消息成功后,会向kafka内部topic(如图)提交自己offset偏移量,记录自己的消费offset,共提供了50个分区。提交的数据格式为key-value键值对,通过对key值进行hash运算,将记录更新到对应的分区,key:consumerGroupId+topic+分区号,value:offset,kafka会定期清理旧数据,保留最新的数据
消费者Rebalance机制
当kafka集群中topic内部分区或消费者组中消费者发生变化,kafka会重新分配他们之间的消费关系, 始终维持着一个partition只能被一个消费者消费,一个消费者组可以消费多个topic下的partition的关系
以下几种情况可能会触发Rebalance机制:
1、消费者组里面新增或减少了消费者
2、动态给topic添加分区
3、消费者组订阅了新的topic
注意:rebalance过程中,消费者无法从kafka消费消息,这对kafka的TPS会有影响
Rebalance过程
1、选择组协调器(broker):消费者组会选择一个broker作为自己的组协调器,负责监听这个消费者组的所有消费者的心跳,以及判断是否宕机。每个消费者启动以后都会向kafka集群某个broker发送请求查找自己的组协调器,并与其建立网络连接
2、加入消费组:找到组协调器后,消费者会向组协调器发送加入消费组的请求。组协调器选择第一个加入消费组的consumer作为组长,把消费组的元数据发送给组长。组长根据这些元素指定分区方案。
3、 组长把分区方案发送给组协调器,组协调器会下发给其他组内消费者。
分区方案
范围(range):根据topic分区数对订阅该topic的消费组的消费者数量做除法取整和求余运算,将分区按范围划分分配消费组
轮询(round-robin)
sticky:初始分配和轮询一样,但是Rebalance时,会尽可能保证均匀和尽量维持与上次分区类似
kafka的零拷贝
producer发送消息给broker时,日志都是按照顺序写入磁盘,这是kafka吞吐量高的原因之一。如果所发送的消息指定了分区号,则直接append到对应的分区,如没有指定分区则通过对key进行hash算法计算出一个分区号,如果没有key,则轮询选择partition。
HW和LEO(HighWatermark/log-end-offset)
HW:消费者可以消费到的消息,通常是消息已经同步到所有的副本才可以被消费,即Isr列表。
LEO:Leader副本中日志追加的消息,其他follow副本还没有来得及同步更新的offset位置,从HW开始到LEO的消息是不可以被消费者消费的。
当然消费情况是跟acks这个参数有关的。
日志的分段存储
kafka日志文件夹是通过topic+分区号来命名, 具体存储的日志文件是分段存储的,每个分段都会有三个日志文件,分别是index、log和timeindex,其中log格式存储的是数据,而其他两个都是索引文件。index是根据数据的offset构建的部分offset,数据每增加4kb就会将该offset值增加到index文件中,timeindex的原理与此类似,它会多存储一个时间参数。