深入理解Kafka Consumer内部机制
深入理解Kafka Consumer内部机制
本文为深入理解kafka producer/consumer系列文章,前面我们讲到《深入理解Kafka producer内部机制》,本片则从Consumer角度深入理解Kafka Consumer内部机制。
Kafka Consumer 是一个从 Kafka 消费消息的客户端。
基本组件:
Consumer Metadata(消费者元数据)——管理消费者需要的元数据:集群中的主题和分区,充当分区领导者的代理节点等。
Subscriptions(订阅)——跟踪消费者订阅状态
Deserializers(反序列化器)——记录键和值反序列化器。 反序列化器将字节数组转换为对象。
Partition Assignor — 代表实现 org.apache.kafka.clients.consumer.ConsumerPartitionAssignor 的分区分配策略的完全限定类名
Interceptors(拦截器)——可能改变记录的拦截器
Consumer Coordinator——管理组成员、偏移量
Network Client(网络客户端)——处理对代理的请求
Fetcher——从broker那里获取成批的记录。
配置Kafka Consumer
Kafka Consumer 有四个必需的属性:
bootstrap.servers — 主机/端口对列表,用于建立与 Kafka 集群的初始连接。 格式:“host1:port1,host2:port2,...”
key.deserializer — 代表实现 org.apache.kafka.common.serialization.Deserializer 接口的key反序列化器的完全限定类名。
value.deserializer — 表示实现 org.apache.kafka.common.serialization.Deserializer 接口的value反序列化器的完全限定类名。
group.id — 唯一的消费者组 ID。 如果客户端使用 subscribe() 方法来消费消息或使用偏移量管理功能,则需要。
订阅主题
Kafka Consumer 提供了两种订阅主题的方式:通过 subscribe() 和 assign() 方法。 每个都有一组不同的支持功能。
subscribe()
- 支持订阅主题列表或使用正则表达式
- 具有消费者故障检测的组成员身份(客户端和服务器端)
- 动态分区分配
- 自动或手动偏移量管理
- 每个分区单个消费者(使用标准分区分配器)
assign()
- 通过主题分区订阅更好地控制
- 自动或手动偏移量管理
- 每个分区支持多个消费者
Apache Flink 和 Spark 使用 assign() 来订阅主题并管理主题-分区对在工作者之间的分布。
消费数据
一旦订阅了主题,用户就可以通过调用 poll() 方法来消费消息。 根据订阅方法的不同,背后会发生几个调用,在下面的序列图中列出。
使用subscribe()消费
在 subscribe() 的情况下,Kafka Consumer 在成为消费者组的活跃成员之前不会消费记录。 我们看到一些团队忽略了这一点,花时间调试停止消费,而根本原因是消费者群体不稳定。
使用assign()消费
在 assign() 的情况下,Kafka Consumer 不会调用组成员资格功能,例如心跳和加入/重新加入消费者组。
Fetcher
无论采用何种订阅方式,Kafka Consumer 都使用 Fetcher 从 broker 中检索批记录。
Fetcher 在内存中保存生产者发送的压缩批次,并在 poll() 上解压缩记录。 一旦批次被消耗,它就会从内存中丢弃。 fetch.min.bytes 和 fetch.max.wait.ms 是调整 fetcher 吞吐量或延迟的关键配置。 增加字节数和时间将导致吞吐量增加并减少更好的延迟。
消费组
当用户使用 subscribe() 进行消费时,具有相同 group.id 的消费者将组成一个消费组,并协作消费 topic(s) 消息。 Kafka 集群将选出其中一个 broker 作为 Group Coordinator。 组协调器负责管理组列表成员、接收心跳、触发组成员更改的重新平衡等。协调器将选举一个消费者作为组长,并要求跨消费者进行分区分配。 每个分区只会分配一个消费者。
消费者组重新平衡
组成员的变化将触发消费者组重新平衡。 在重新平衡期间,组长将重新计算当前成员之间的分区分配。 当发生如下创景时,重新平衡被触发
- 消费者加入群组
- 消费者离开群体
- 通过 max.poll.interval.ms 检测到客户端故障
- 通过 session.timeout.ms 检测到服务器端故障
可能触发消费者组重新平衡的可能原因列表:
- 服务扩展
- poll() 和长消息处理发生在同一个线程中
- 组协调器的心跳失败
- JVM 垃圾收集暂停
- Kubernetes PODS CPU 节流
- Kubernetes 集群升级,导致 POD 逐出
- 网络问题(延迟、丢包等)
消费者分区分配器
Kafka Consumer 提供了几个选项来选择在重新平衡期间如何分配分区。 用户可以通过 partition.assignment.strategy 配置参数来控制它,其值为实现 org.apache.kafka.clients.consumer.ConsumerPartitionAssignor 的完全限定类名的值。 Kafka 开箱即用地提供以下策略:
范围 - 停止全局策略,以主题为基础。 它可能会产生不平衡的分配。
RoundRobin — 停止全局策略,为相同的订阅统一分配分区。
Sticky——停止全局策略,初始分布会接近RoundRobin。 尝试最小化重新平衡期间移动的分区,可能会产生不平衡的分配。
CooperativeSticky — 在不停止消费的情况下进行增量再平衡。 它与 Sticky 的逻辑相同,但具有增量支持。 这种策略可能会产生不平衡的分配。