点击上方蓝字关注我们 文末有惊喜
kafka架构图
kafka核心控制器
定义
在kafka集群中,会选举出一个broker作为控制器(controller),负责管理集群中所有的分区和副本的状态;
职责
-
监听broker变化,通过监听Zookeeper中的/brokers/ids/ 节点方式来实现 -
监听topic变化,通过监听Zookeeper中的/brokers/topics节点方式来实现,实时监听topic变化 -
管理topic、partition、broker相关的信息 -
更新数据的元数据信息,同步到其他的broker节点
选举过程
broker控制器选举的原理是借助于zookeeper的临时节点实现:kafka集群启动时,每个broker都会尝试争当控制器,都会往zookeeper的controller节点注册自己,但是由于zookeerper的特性,如果节点已经创建过,再创建就会失败,所以只会有一个broker创建成功,那么创建成功的broker就会成为控制器;此外其他broker都会监听这个controller节点
由于controller是临时节点,当控制器broker挂机之后,就会断开与zookeeper的会话连接,临时节点也会消失,其它节点监听到controller节点消失后,就会重新争取controller节点。
Partition副本选择机制
当controller感知到副本leader所在的broker宕机之后,会在当前副本所在的副本列表中选出第一个副本所在的broker作为副本leader,并且要保证这个broker一定要在副本的ISR(存活的副本broker)集合中,如果第一个不存在,则继续尝试第二个第三个,直到满足;不知道为啥kafka作者为什么不直接在ISR集合里面挑,非得多一步操作
消费者消费的offset如何记录?
每个消费者消费所在分区的offset都会记录在kafka的内部topic中(__consumer_offsets),kafka默认会为这个topic创建50个分区,用来抵抗高并发;提交到这个topic的时候,key是当前消费者所处的消费组ID+topic+分区号,value就是当前offset的值,那么kafka会把这个消息发送到哪个分区呢,是由以下公式决定的:hash(consumer group id) % __consumer_offsets主题的分区数(默认50),consumer每次消费前都会从这里获取offset值;
什么是消费者rebalance?
定义
当某个消费组中的消费者挂掉或退出之后,此时就会自动把分配给它的分区分配给其它消费者(没有被指定消费分区的消费者),不仅如此,当有新的消费者加入后也会触发rebalance操作。
Rebalance过程
-
选择组协调器(GroupCoordinato) 因为每个消费组的消费offset提交到的分区是确定的,即通过公式hash(consumer group id) % __consumer_offsets主题的分区数计算而来,所以kafka就直接把这个提交的分区所在的副本leader当作组协调器。
-
加入消费组 JOIN GROUP 在选好组协调器之后,接下来就是加入消费组阶段,在此阶段的消费者会向 GroupCoordinator 发送 JoinGroupRequest 请求,并处理响应,然后GroupCoordinator 从一个consumer group中选择第一个加入group的consumer作为leader(消费组协调器),把consumer group情况发送给这个leader,接着这个leader会负责制定分区方案。
-
SYNC GROUP consumer leader通过给GroupCoordinator发送SyncGroupRequest,接着GroupCoordinator就把分区方案下发给各个consumer,他们会根据指定分区的leader broker进行网络连接以及消息消费。
Rebalance分区分配策略
通过在消费者客户端配置参数partition.assignment.strategy 来设置分配策略,默认为range
-
range 假如现在有10个分区,4个消费者,那么第一步计算平均每个消费者分配的分区数:10/4 = 2,这样每个消费者分到两个分区,还剩余 2 个分区,那么把剩下的两个分区分别分给前面两个消费者,最终分配结果:
第一个消费者:0,1,2 第二个消费者:3,4,5 第三个消费者:6,7 第四个消费者:8,9
-
round-robin(轮询分配) 很容易理解,同上有10个分区,4个消费者:
第一个消费者:0,4,8 第二个消费者:1,5,9 第三个消费者:2,6 第四个消费者:3,7
-
sticky
假如目前分区分配如下:
第一个消费者:0,4,8 第二个消费者:1,5,9 第三个消费者:2,6 第四个消费者:3,7
现在如果第四个消费者挂机,则重新分配后如下:第一个消费者:0,4,8,7 第二个消费者:1,5,9 第三个消费者:2,6,3
如果两个规则冲突,优先保证第一个原则
-
分区尽可能均匀 -
分区的分配尽可能与上次分配相同
producer发布消息过程
-
写入方式 生产者使用push模式将消息发布到broker中,每条消息都被追加到partition中,属于顺序写磁盘 -
broker根据以下规则将消息发布到指定分区中
-
如果指定分区,则直接发到指定分区 -
如果没有指定分区,则根据key进行hash 取模分区数,得到分区 -
key和partition 都没有指定,则使用轮训方式
-
发送流程
重要参数acks解释:
-
ack=0 指producer把消息发送出去,不需要等待任何回应,就认为消息发送成功 -
ack=1 指producer把消息发送到leader之后,leader把消息写入磁盘,并回复producer ACK,则producer就认为消息发送成功 -
ack=all/-1 指producer把消息发送到leader之后,leader写入磁盘后,还要等待其他副本的ACK,只有都写成功了,leader才给producer回复ACK,这时producer才认为消息发送成功
-
producer从zookeeper的state节点中中找到副本leader所在brokerid -
producer把消息发送到该leader -
leader将消息写入log -
follower从leader拉取消息,写入本地log后向leader回复ack -
leader收到所有ISR里面的副本恢复ACK之后,增加HW,并向producer发送ACK
HW与LEO到底是个啥?
HW俗称高水位,又称消费能消费到的最大offset,LEO是broker内部能看到的最大offset, 那么这个最大的offset是怎么产生的呢?正常情况下,LEO的offset和HW的offset是相同的 当有新消息发送到leader之后,leader的LEO就会增加,这个时候LEO的offset就与HW的offset不一样了,接下来副本开始拉取leader消息,对应的副本LEO也会增加,等到最后一个副本同步完成消息之后,LEO和HW的offset就会一致,这样做的目的是什么呢?是为了「数据的一致性」,保证消息同步完成后才能对消费者可见。
2020-12-02
2020-11-24
2020-11-23
2020-11-21
成长心路 | 优质书单 | 面试资料
牛人故事 | 前沿技术 | 视频教程
本文分享自微信公众号 - AI码师(shi_ma_AI)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/4005157/blog/4956197