基于Kafka2.1解读Consumer原理

概要

继上一篇讲Producer原理的文章过去已经一个多月了,今天来讲讲Consumer的原理。
其实源码早就读了部分了,但是最近工作比较忙,一直没空写文章。

整体架构流程

Consumer组件图

技术名词解释

  • coordinator:Consumer协调器,负责管理Consumer需要加入到哪个消费组、消费哪个partition、提交offset等操作
  • fetcher:主要作用是获取待消费的records,也是Consumer端最重要的组件
  • keyDeserializer:对record中的key进行反序列化
  • valueDeserializer:对record中的value进行反序列化
  • client:执行RPC请求时的网络client,当然会包括一些Kafka内部的操作

技术细节

coordinator

其实协调器对于Consumer的处理分为几个阶段:

  1. Consumer加入的时候:负责判断Consumer加入到哪个Consumer group、协调消费哪个partition
  2. Consumer消费过程中:负责记录Consumer消费的partition的元数据、partition的消费状态、消费offset;更新partition的offset

fetcher

fetcher的数据结构
从Fetcher的数据结构里其实就可以猜到它的作用:缓存已Fetch到的records、去fetch更多的records

  • completedFetch:每次fetch请求得到的数据,拆分到topicPartition维度。因为fetch请求是基于server的node维度,请求回来的数据按照tp维度拆分,得到不同的completedFetch
  • completedFetchs: 已经fetch到的所有completedFetch
  • nextInLineRecords:当前正在被消费消息的completedFetch对应的所有records,由于对于同一个tp,当时Producer发消息时,是按照batch维度发送的,所以此时completedFetch里也包含多个batch,每个batch包含多个record,也就是records
    如果缓存里没有消息呢?
    也就是completedFetchs和nextInLineRecords都是空

client

类型是ConsumerNetworkClient,里面包含了一个NetWorkClient。至于NetWorkClient是如何进行数据处理及RPC的,可以参考Producer原理解析那篇文章
client示意图

  • unsent:保存的是当前需要发送的fetchRequest
  • pendingCompletion:需要被处理的已完成的请求,其实也就是之前的fetchRequest的response
  • client:该client是NetWorkClient,Producer端是直接使用了该client
    所以ConsumerNetworkClient的主要作用:1. 处理之前fetch回来的数据;2. 调用NetWorkClient将当前的fetchRequest发送出去

consumer#poll的主要流程

  1. 判断是否需要commit offset(默认情况下,5秒进行一次异步offset的commit)

  2. 读取Fetcher的缓存,如果有数据,直接跳转到5

  3. 缓存里没有数据,基于coordinator里保存的partition元数据,封装fetchRequest
    创建fetchRequest示意图

  4. 执行client#poll:1. 处理之前fetch回来的数据,解析为completedFetchs;2. 调用NetWorkClient将当前的fetchRequest发送出去;
    client#poll逻辑示意图

  5. 调用自定义的消费逻辑(程序员自己写的Consumer),处理records

全局总览

kafkaConsumer示意图

小结

可以看到Consumer和Producer在逻辑处理上还是有较大不同的。

组件处理请求处理方式
producer主要处理发送消息。对应RPC,主要是写请求将业务逻辑和IO逻辑解耦。业务逻辑:组装batch;IO逻辑:基于batch组装request并发送request
consumer既要发送fetchRequest,同时还要处理fetchResponse。对于RPC,读写请求都占比较大业务逻辑和IO逻辑解耦,但是串行化。业务逻辑:从fetcher里poll已经fetch到的数据;IO逻辑:基于partition元数据组装fetchRequest,处理fetchResponse,发送fetchRequest

Producer的IO是一个Sender线程在异步运行,为什么Consumer不这么干呢?
笔者觉得原因是:
Producer的逻辑是把消息往外发,所以Sender运行的越快,client这边为了维护batch而消耗的资源(内存和CPU越少);而如果Consumer也这么干,实际消费速度赶不上fetch速度的话,会需要额外的内存和CPU资源来维持更多的completedFetchs,更别说如果发生了rebalance的话,fetch过来的completedFetchs可能都是白fetch了。所以,总结下:1. 兼顾消费速度;2. 兼顾client的资源消耗&性能

Kafka 2.1 版本的安装包可以通过 Apache Kafka 的官方资源进行下载。根据历史版本的发布情况,Kafka 的发布通常会提供与不同 Scala 版本兼容的版本,例如 `kafka_2.11` 或 `kafka_2.12`。Kafka 2.1 版本对应的 Scala 版本通常是 2.112.12。 ### 下载方式 1. **通过清华大学镜像下载 Kafka 2.1 版本** 清华大学开源软件镜像站提供了 Kafka 的历史版本下载地址。可以使用以下命令下载 Kafka 2.1 版本(以 Scala 2.12 为例): ```bash wget http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.1.1/kafka_2.12-2.1.1.tgz ``` 如果需要其他 Scala 版本(如 2.11),可以将 `kafka_2.12-2.1.1.tgz` 替换为 `kafka_2.11-2.1.1.tgz`。 2. **通过 Apache Kafka 官方下载页面** Kafka 的官方下载页面提供了历史版本的下载链接,可以通过以下 URL 访问: - 官方地址:[https://kafka.apache.org/downloads](https://kafka.apache.org/downloads) 在页面中找到 Kafka 2.1 版本,并选择适合的 Scala 版本进行下载。 3. **验证下载版本的兼容性** Kafka 2.1 版本通常依赖特定的 Scala 和 Gradle 配置。例如,在构建 Kafka 源码时,需确保 `gradle.properties` 文件中的 `scalaVersion` 与安装环境一致。例如,Kafka 2.1 版本可能使用 `scalaVersion=2.11.8` 或 `scalaVersion=2.12.10` [^2]。 4. **解压安装包** 下载完成后,可以使用以下命令解压 Kafka 安装包: ```bash tar -xzf kafka_2.12-2.1.1.tgz ``` 5. **构建 Kafka 源码(可选)** 如果需要从源码构建 Kafka 2.1 版本,确保 Gradle 配置正确,并使用以下命令进行构建: ```bash ./gradlew jar ``` 同时,确保 `gradle.properties` 文件中配置的 `scalaVersion` 和 `zookeeper` 版本与构建环境一致 [^4]。 --- ### 注意事项 - **Scala 版本选择**:Kafka 的版本命名中包含 Scala 版本信息,如 `kafka_2.12-2.1.1` 表示该版本使用 Scala 2.12 构建。选择时需确保与运行环境的 Scala 版本兼容。 - **ZooKeeper 依赖**:Kafka 依赖 ZooKeeper 进行集群协调,建议使用 ZooKeeper 3.5.x 或更高版本。 - **Gradle 配置**:如果需要构建源码,确保 `gradle.properties` 中的 `gradle` 和 `zookeeper` 版本与构建要求一致 [^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值