Kafka Consumer设计解析

High Level Consumer

  • Consumer Group

  • Rebalance场景剖析

Low Level Consumer

很多时候,客户程序只是希望从Kafka读取数据,不太关心消息offset的处理。同时也希望提供一些语义,例如同一条消息只被某一个Consumer消费(单播)或被所有Consumer消费(广播)。因此,Kafka Hight Level Consumer提供了一个从Kafka消费数据的高层抽象,从而屏蔽掉其中的细节并提供丰富的语义
Consumer Group
1. 什么是消费者组
High Level Consumer将从某个Partition读取的最后一条消息的offset存于Zookeeper或专用Topic中。这个offset基于客户程序提供给Kafka的名字来保存,这个名字被称为Consumer Group。Consumer Group是整个Kafka集群全局的,而非某个Topic的。每一个High Level Consumer实例都属于一个Consumer Group,若不指定则属于默认的Group。组内的所有消费者协调在一起来消费订阅主题的所有分区,每个分区只能由同一个消费组内的一个Consumer来消费
o Consumer Group下可以有一个或多个Consumer instance,Consumer instance可以是一个进程,也可以是一个线程
o group.id是一个字符串,唯一标识一个Consumer Group
o Consumer Group下订阅的Topic下的每个分区只能分配给某个Group下的一个Consumer
2. 消费者位置
消费者在消费的过程中需要记录自己消费了多少数据,即消费位置信息。在Kafka中这个位置信息有个专门的术语:位移(offset)。很多消息引擎都把这部分信息保存在服务器端(Broker端)。这样做的好处当然是实现简单,但会有三个主要的问题:

  1. Broker从此变成有状态的,会影响伸缩性
  2. 需要引入应答机制(Acknowledgement)来确认消费成功
  3. 由于要保存很多Consumer的offset信息,必然引入复杂的数据结构,造成资源浪费
    而Kafka选择了不同的方式:每个Consumer Group保存自己的位移信息,那么只需要简单的一个整数表示位置就够了;同时可以引入checkpoint机制定期持久化,简化了应答机制的实现

3. 位移管理
0. 自动VS手动
Kafka默认是定期帮你自动提交位移的(enable.auto.commit = true),你当然可以选择手动提交位移实现自己控制。另外kafka会定期把group消费情况保存起来,做成一个offset map,如下图所示:
在这里插入图片描述

上图中表明了test-group这个组当前的消费情况

  1. 位移提交
    老版本的位移是提交到zookeeper中,但是Zookeeper其实并不适合进行大批量的读写操作;因此kafka提供了另一种解决方案:增加__consumer_offsets Topic,将offset信息写入这个Topic,摆脱对Zookeeper的依赖(指保存offset这件事情)。__consumer_offsets中的消息保存了每个Consumer Group某一时刻提交的offset信息。依然以上图中的Consumer Group为例,格式大概如下:

__consumers_offsets Topic配置了Compact策略,使得它总是能够保存最新的位移信息,既控制了该Topic总体的日志容量,也能实现保存最新offset的目的
4. Rebalance
0. 什么是Rebalance?
Rebalance本质上是一种协议,规定了一个Consumer Group下的所有Consumer如何达成一致来分配订阅Topic的每个分区。比如某个Group下有20个Consumer,它订阅了一个具有100个分区的Topic。正常情况下,Kafka平均会为每个consumer分配5个分区。这个分配的过程就叫Rebalance。

  1. 什么时候Rebalance?
    这也是经常被提及的一个问题。Rebalance的触发条件有三种:
     组成员发生变更(新Consumer加入组、已有Consumer主动离开组或已有Consumer崩溃了)
     订阅主题数发生变更,使用正则表达式的方式进行订阅,那么新建匹配正则表达式的Topic就会触发Rebalance
     订阅主题的分区数发生变更

  2. 如何进行组内分区分配?
     Range
    Range策略是对每个主题而言的,首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。然后将partitions的个数除于消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。
     RoundRobin
    使用RoundRobin策略有两个前提条件必须满足:1、同一个Consumer Group里面的所有消费者的num.streams必须相等;2、每个消费者订阅的主题必须相同。将所有主题的分区组成TopicAndPartition列表,按分区名Hash排序后平均分配给每一个消费者的线程
     自定义可插拔式的分配策略

  3. 谁来执行Rebalance和Consumer Group管理?
    每个Consumer Group都会被分配一个Coordinator用于组管理和位移管理,Consumer Group的第一个Consumer启动的时候,它会去和Kafka Server确定谁是它们组的Coordinator。之后该Group内的所有成员都会和该Coordinator进行协调通信

  4. Rebalance Generation
    Rebalance一次,更新新一届的Consumer Group成员,Generation + 1

  5. 协议
    Rebalance本质上是一组协议。Group与Coordinator共同使用它来完成Group的Rebalance。目前Kafka提供了5个协议来处理与Consumer Group Coordination相关的问题:
     Heartbeat请求:Consumer需要定期给Coordinator发送心跳来表明自己还活着
     LeaveGroup请求:主动告诉Coordinator我要离开Consumer Group
     SyncGroup请求:Group Leader把分配方案告诉组内所有成员
     JoinGroup请求:成员请求加入组
     DescribeGroup请求:显示组的所有信息,包括成员信息,协议名称,分配方案,订阅信息等。通常该请求是给管理员使用
    Coordinator在Rebalance的时候主要用到了前面4种请求

  6. Rebalance过程
    Rebalance分为2步:Join和Sync

  7. Join,顾名思义就是加入组。这一步中,所有成员都向Coordinator发送JoinGroup请求,请求入组。一旦所有成员都发送了JoinGroup请求,Coordinator会从中选择一个Consumer担任Leader的角色,并把组成员信息以及订阅信息发给Leader–注意Leader和Coordinator不是一个概念。Leader负责消费分配方案的制定

  8. Sync,这一步Leader开始分配消费方案,即哪个Consumer负责消费哪些Topic的哪些Partition。一旦完成分配,Leader会将这个方案封装进SyncGroup请求中发给Coordinator,非Leader也会发SyncGroup请求,只是内容为空。Coordinator接收到分配方案之后会把方案塞进SyncGroup的Response中发给各个Consumer。这样组内的所有成员就都知道自己应该消费哪些分区了

  9. Consumer Group状态机
    Group也做了个状态机来表明组状态的流转。coordinator根据这个状态机会对consumer group做不同的处理,如下图所示:

简单说明下图中的各个状态:
 Dead:组内已经没有任何成员的最终状态,组的元数据也已经被Coordinator移除了。这种状态响应各种请求都是一个Response: UNKNOWN_MEMBER_ID
 Empty:组内无成员,但是位移信息还没有过期。这种状态只能响应JoinGroup请求
 PreparingRebalance:组准备开启新的Rebalance,等待成员加入
 AwaitingSync:正在等待Leader Consumer将分配方案传给各个成员
 Stable:Rebalance完成!可以开始消费了
Rebalance场景剖析

  1. 新成员加入组

  2. 组成员崩溃
    组成员崩溃和组成员主动离开是两个不同的场景。因为在崩溃时成员并不会主动地告知Coordinator此事,Coordinator有可能需要一个完整的session.timeout周期才能检测到这种崩溃,这必然会造成Consumer的滞后。可以说离开组是主动地发起Rebalance;而崩溃则是被动地发起Rebalance

  3. 组成员主动离组

  4. 提交位移

Low Level Consumer

  1. 使用Low Level Consumer (Simple Consumer)的主要原因是,用户希望比Consumer Group更好的控制数据的消费。比如:
    o 同一条消息读多次
    o 只读取某个Topic的部分Partition
    o 管理事务,从而确保每条消息被处理一次,且仅被处理一次
  2. 与Consumer Group相比,Low Level Consumer要求用户做大量的额外工作:
    o 必须在应用程序中跟踪offset,从而确定下一条应该消费哪条消息
    o 应用程序需要通过程序获知每个Partition的Leader是谁
    o 必须处理Leader的变化
  3. 使用Low Level Consumer的一般流程如下:
    1. 查找到一个“活着”的Broker,并且找出每个Partition的Leader
    2. 找出每个Partition的Follower
    3. 定义好请求,该请求应该能描述应用程序需要哪些数据
    4. Fetch数据
    5. 识别Leader的变化,并对之作出必要的响应
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值