Kafka 0.8 Consumer设计解析
摘要
本文主要介绍了Kafka High Level Consumer,Consumer Group,Consumer Rebalance,Low Level Consumer实现的语义,以及适用场景。以及未来版本中对High Level Consumer的重新设计–使用Consumer Coordinator解决Split Brain和Herd等问题。
1.High Level Consumer
很多时候,客户程序只是希望从Kafka读取数据,不太关心消息offset的处理。同时也希望提供一些语义,例如同一条消息只被某一个Consumer消费(单播)或被所有Consumer消费(广播)。因此,Kafka Hight Level Consumer提供了一个从Kafka消费数据的高层抽象,从而屏蔽掉其中的细节并提供丰富的语义。
1.1 Consumer Group
High Level Consumer将从某个Partition读取的最后一条消息的offset存于Zookeeper中。这个offset基于Consumer Group来识别的。Consumer Group是整个Kafka集群全局的,而非某个Topic的。每一个High Level Consumer实例都属于一个Consumer Group。
(Kafka从0.8.2版本开始同时支持将offset存于Zookeeper中与将offset存于专用的Kafka Topic:__consumer_offsets中)
Zookeeper中Consumer相关节点如下图所示
为了实现传统Message Queue消息只被消费一次的语义,Kafka保证每条消息在同一个Consumer Group里只会被某一个Consumer消费。与传统Message Queue不同的是,Kafka还允许不同Consumer Group同时消费同一条消息,这一特性可以为消息的多元化处理提供支持。
Kafka的设计理念之一就是同时提供离线处理和实时处理。
1.2 High Level Consumer Rebalance
(本节所讲述Rebalance相关内容均基于Kafka High Level Consumer-0.8版本的)
Rebalance的触发条件,自己复习复习。
Consumer Rebalance的算法如下:
- 将目标Topic下的所有Partirtion排序,存于Pt
- 对某Consumer Group下所有Consumer排序,存于Cg,第i个Consumer记为Ci
N = size(Pt) / size(Cg)
,向上取整- 解除Ci对原来分配的Partition的消费权(i从0开始)
- 将第i∗N到
(i+1)∗N−1
个Partition分配给Ci
最新版(0.8.2.1)Kafka的Consumer Rebalance的控制策略是由每一个Consumer通过在Zookeeper上注册Watch完成的。每个Consumer被创建时会触发Consumer Group的Rebalance,具体启动流程如下:
- High Level Consumer启动时将其ID注册到其Consumer Group下,在Zookeeper上的路径为
/consumers/[consumer group]/ids/[consumer id]
- 在/consumers/[consumer group]/ids上注册Watch
- 在/brokers/ids上注册Watch
- 如果Consumer通过Topic Filter创建消息流,则它会同时在/brokers/topics上也创建Watch
- 强制自己在其Consumer Group内启动Rebalance流程
在这种策略下,每一个Consumer或者Broker的增加或者减少都会触发Consumer Rebalance。因为每个Consumer只负责调整自己所消费的Partition,为了保证整个Consumer Group
的一致性,当一个Consumer触发了Rebalance时,该Consumer Group内的其它所有其它Consumer也应该同时触发Rebalance。
该方式有如下缺陷:
- Herd effect
任何Broker或者Consumer的增减都会触发所有的Consumer的Rebalance - Split Brain
每个Consumer分别单独通过Zookeeper判断哪些Broker和Consumer 宕机了,那么不同Consumer在同一时刻从Zookeeper“看”到的View就可能不一样,这是由Zookeeper的特性决定的,这就会造成不正确的Reblance尝试。 - 调整结果不可控
所有的Consumer都并不知道其它Consumer的Rebalance是否成功,这可能会导致Kafka工作在一个不正确的状态。
1.3 Coordinator
当前版本的High Level Consumer存在Herd Effect和Split Brain的问题。如果将失败探测和Rebalance的逻辑放到一个高可用的中心Coordinator,那么这两个问题即可解决。同时还可大大减少Zookeeper的负载,有利于Kafka Broker的Scale Out。
每一个Broker将被选举为某些Consumer Group的Coordinator。某个Cosnumer Group的Coordinator负责在该Consumer Group的成员变化或者所订阅的Topic的Partititon变化时协调Rebalance操作。
Consumer状态机
- Down:Consumer停止工作
- Start up & discover coordinator:Consumer检测其所在Group的Coordinator。一旦它检测到Coordinator,即向其发送JoinGroupRequest。
- Part of a group:该状态下,Consumer已经是该Group的成员,并周期性发送HeartbeatRequest。如HeartbeatResponse包含IllegalGeneration错误码,则转换到Stopped Consumption状态。若连接丢失,HeartbeatResponse包含NotCoordinatorForGroup错误码,则转换到Rediscover coordinator状态。
- Rediscover coordinator:该状态下,Consumer不停止消费而是尝试通过发送ConsumerMetadataRequest来探测新的Coordinator,并且等待直到获得无错误码的响应。
- Stopped consumption:该状态下,Consumer停止消费并提交offset,直到它再次加入Group。
3.Low Level Consumer
使用Low Level Consumer (Simple Consumer)的主要原因是,用户希望比Consumer Group更好的控制数据的消费。比如:
- 同一条消息读多次
- 只读取某个Topic的部分Partition
- 管理事务,从而确保每条消息被处理一次,且仅被处理一次
与Consumer Group相比,Low Level Consumer要求用户做大量的额外工作。
- 必须在应用程序中跟踪offset,从而确定下一条应该消费哪条消息
- 应用程序需要通过程序获知每个Partition的Leader是谁
- 必须处理Leader的变化
使用Low Level Consumer的一般流程如下
- 查找到一个“活着”的Broker,并且找出每个Partition的Leader
- 找出每个Partition的Follower
- 定义好请求,该请求应该能描述应用程序需要哪些数据
- Fetch数据
- 识别Leader的变化,并对之作出必要的响应
如果kafka partition 的leader发生了切换,是如何影响正在消费的consumer的?
- consumer监听了topicPartition的更新,所以可以正常的切换到新的leader。有offset的存在,high water的存在,从上次的 offset 开始读,那就不会有不一致的问题。
- 所以在一般正常情况下,当 kafka 发生 failover 的时候,consumer 是不会读到不一致数据的。特例的情况就是,当前 leader 是唯一有效的 replica,其他replica都处在完全不同步状态,这样发生 leader 切换,一定是会丢数据的,并会发生 offset 不一致。
posted on 2017-02-06 21:17 BYRHuangQiang 阅读(800) 评论(0) 编辑 收藏 举报