历史文章:
kafka(一)kafka的基础与常用配置
由消费者组成的存在一个或多个消费者实例成为消费者组,这些消费者实例共享一个igroup id。
消费者组内的所有成员一起订阅某个主题的所有分区,每个分区只能由消费者组内的其中一消费者订阅。
下图是kakfa官网上给出的说明:
可以看到消费者组中的消费者会消费不同分区,当消费者组中的消费者数量发生变化时,这时候就会触发kafka中的rebalance
重平衡的触发条件有三个:
在重平衡的过程中,**消费者将无法从分区中消费消息,因为此时需要重新分配分区给组内的消费者。**如果kafka集群内有很多节点,那么重平衡可能导致严重的性能问题,在重新分配分区的阶段,kafka基本上处于不可用状态。所以在实际环境中,应该尽量避免重平衡发生。
kafka中有三种重平衡策略
组内的消费者会基于topic平均分配topic中的分区。如果主题中的分区分区不能平均分配给组内每个消费者,那么某个消费者会分配到额外的分区。
假如目前有两个消费者1和消费者2,topicA中有三个分区t1,t2,t3,topicB中有三个分区a1,a2,a3。
rebalance后的结果:
RoundRobin是基于全部主题的分区来进行分配的,这是是kafka默认的rebalance分区策略。还是用刚刚的例子来看,
举假如目前有两个消费者1和消费者2,topicA中有三个分区t1,t2,t3,topicB中有三个分区a1,a2,a3。
rebalance后的结果:
Sticky分配策略是最新的也是最复杂的策略,其具体实现位于package org.apache.kafka.clients.consumer.StickyAssignor。
这种分配策略是在0.11.0才被提出来的,主要是为了一定程度解决上面提到的重平衡非要重新分配全部分区的问题。称为粘性分配策略。
听名字就知道,主要是为了让目前的分配尽可能保持不变,只挪动尽可能少的分区来实现重平衡。
还是举例说明,有三个消费者C0,C1,C2 。三个主题t0,t1,t2,t3。每个主题各有两个分区, t0p0,t0p1,t1p0,t1p1,t2p0,t2p1,t3p0,t3p1。
现在订阅情况如下:
假设现在C1挂掉了,如果是RoundRobin分配策略,那么会变成下面这样:
就是说它会全部重新打乱,再分配,而如何使用Sticky分配策略,会变成这样:
Kafka 为消费者组定义了 5 种状态,它们分别是:
消费者会向协调者发送两个请求:
JoinGroup:申请加入消费者组
SyncGroup:分配方订阅案
消费者在申请加入消费者组的时候,会向协调者发送JoinGroup请求,协调者收到请求后会选择一个消费者担任领导者。通常情况下,第一个发送的成员会自动成为领导者。这里的领导者主要作用是收集所有消费者的信息并制定分配方案。
领导者完成方案分配后,会通过SyncGroup命令,将分配方案发给协调者。其他消费者也会向协调者发送SyncGroup命令,请求不包含任何信息,返回会携带当前消费者的分配信息,包含哪个分区等。
以下几个场景会触发重平衡:
重平衡会导致一定程度的阻塞,导致消费者处于不可用状态。
要说完全避免重平衡,那是不可能的,因为你无法完全保证消费者不会故障。而消费者故障其实也是最常见的引发重平衡的地方,所以要尽量避免重平衡。
在实际场景中,有部分情况会让kafka错误地认为一个正常的消费者已经挂掉了,我们需要避免这样的情况出现。
为什么会出现这种情况?
在分布式系统中,通常是通过心跳来维持分布式系统的,某些场景由于网络问题没接收到心跳,导致kafka认为消费者挂了,而重新开始重平衡。kafka提供了一个参数:session.timout.ms 。这个参数是用来判断多少时间内没有心跳请求的消费者,我们认为他是真正挂了。
另一个参数:heartbeat.interval.ms。这个参数控制发送心跳的频率,频率越高越不容易被误判,当然也会消耗更多的cpu资源。