小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
kafka是一个分布式流平台,高吞吐量的消息系统。非常经典的是用于削峰、解耦、异步。
更多解释请看 【简约入门】消息队列,以kafka开始
本文针对kafka的Leader选举、consumer group、offset这些术语和它们的作用简单的用图来解释一下。
Leader选举
- Leader选举过程
Kakfa Broker Leader
的选举:Kakfa Broker
集群受zookeeper
管理。所有的Kafka Broker
节点一起去zookeeper
上注册一个临时节点,因为只有一个Kafka Broker
会注册成功,其他的都会失败,所以这个成功在zookeeper
上注册临时节点的这个Kafka Broker
会成为Kafka Broker Controller
,其他的Kafka broker
叫Kafka Broker follower
。(这个过程叫Controller
在ZooKeeper
注册Watch
)。
这个controller
会监听其他的Kafka Broker
的所有信息,如果这个kafka broker controller
宕机了,在zookeeper
上面的那个临时节点就会消失。
- broker宕机,副本成为leader
例如:一旦有一个broker
宕机了,这个kafka broker controller
会读取该宕机broker
上所有的partition
在zookeeper
上的状态,并选取ISR
列表中的一个replica
作为partition leader
(如果ISR
列表中的replica
全挂,选一个幸存的replica
作为leader
;
如果该partition
的所有的replica
都宕机了,则将新的leader
设置为-1,等待恢复,等待ISR
中的任一个Replica
“活”过来,并且选它作为Leader
;或选择第一个“活”过来的replica
(不一定是ISR
中的)作为Leader
),这个broker
宕机的事情,kafka controller
也会通知zookeeper
,zookeeper
就会通知其他的kafka broker
。
Consumer group
- consumer消费规则
kafka
中的group
由多个consumer
组成,topic
下面的partition
中的每条消息只能被consumer group
中的一个consumer
消费,如果想多个consumer
消费这条消息,那么这些consumer
必须在不同的组。Kafka
不支持一个partition
中的消息由两个或两个以上的同一个consumer group
下的consumer thread
来处理,除非再启动一个新的consumer group
,代码中常常不同服务设置不同的组名。所以如果想同时对一个topic
做消费的话,启动多个consumer group
就可以了。
但是要注意的是,这里的多个consumer
的消费都必须是顺序读取partition
里面的消息,新启动的consumer
默认从partition
队列最头端的地方开始读消息。kafka
为了保证吞吐量,只允许同一个consumer group
下的一个consumer
线程去访问一个partition
。
如果觉得效率不高的时候,可以加partition
的数量来横向扩展,那么再加新的consumer thread
去消费。如果想多个不同的业务都需要这个topic
的数据,起多个consumer group
就好了,大家都是顺序的读取消息,offset
的值互不影响。这样没有锁竞争,充分发挥了横向的扩展性,吞吐量极高。这也就形成了分布式消费的概念。
- 最优的消费配置
当启动一个consumer group
去消费一个topic
的时候,无论topic
里面有多个少个partition
,无论我们consumer group
里面配置了多少个consumer thread
,这个consumer group
下面的所有consumer thread一定会消费全部的partition;即便这个consumer group
下只有一个consumer thread
,那么这个consumer thread
也会去消费所有的partition
。因此,最优的设计就是,consumer group
下的consumer thread
的数量等于partition
数量,这样效率是最高的。
一个consumer group
下,无论有多少个consumer
,这个consumer group
一定回去把这个topic
下所有的partition
都消费了。当consumer group
里面的consumer
数量小于这个topic
下的partition
数量的时候,就会出现一个conusmer thread
消费多个partition
的情况,总之是这个topic
下的partition
都会被消费。
如果consumer group
里面的consumer
数量等于这个topic
下的partition
数量的时候,此时效率是最高的,每个partition
都有一个consumer thread
去消费。当consumer group
里面的consumer
数量大于这个topic
下的partition
数量的时候,就会有一个consumer thread
空闲。因此,我们在设定consumer group
的时候,只需要指明里面有几个consumer
数量即可,无需指定对应的消费partition
序号,consumer
会自动进行rebalance
。
offset更新策略
- offset的更新
consumer
消费partition
里面的消息的时候是O(1)顺序读取的。所以必须维护着上一次读到哪里的offset
信息。offset
一般存于zookeeper
中,low level API
的offset
由自己维护。consumer
默认是读完消息先commmit
再处理这条消息,autocommit
默认是true
,这时候先commit
就会更新offset
+1,一旦处理失败,offset
已经+1,这个时候就会丢消息;也可以配置成读完消息处理再commit
,这种情况下consumer
端的响应就会比较慢的,需要等处理完才行。
- 消费提交offset过程
Kafka producer
发送消息不用维护消息的offset
信息,因为这个时候,offset
就相当于一个自增id
,producer
就尽管发送消息就好了。而且Kafka
与ActiveMQ
不同,ActiveMQ
大都用在处理业务逻辑上,而Kafka
大都是处理日志,所以Kafka
的producer
一般都是大批量的batch
发送消息,向这个topic
一次性发送一大批消息,load balance
到一个partition
上,一起插进去,offset
作为自增id
自己增加就好。
但是consumer
端是需要维护这个partition
当前消费到哪个offset
信息的,并且kakfa
处理消息是没有锁操作的。因此如果处理消息失败,此时还没有commit offset
+1,当consumer thread
重启后会重复消费这条消息。但是作为高吞吐量高并发的实时处理系统,at least once
的情况下,至少一次会被处理到,是可以容忍的。如果无法容忍,就得使用自己程序维护这个offset
信息,那么想什么时候commit offset
+1就自己控制了。
参考
- 《Kafka 权威指南》
- kafka.apache.org/
- Kafka史上最详细原理总结上
近期评论