kafka (三)

消费

        订阅topic是以一个消费组来订阅的,一个消费组里面可以有多个消费者。同一个消费组中的两个消费者,不会同时消费一个partition。换句话来说,就是一个partition,只能被消费组里的一个消费者消费,但是可以同时被多个消费组消费。因此,如果消费组内的消费者如果比partition多的话,那么就会有个别消费者一直空闲。

API

        订阅topic时,可以用正则表达式,如果有新topic匹配上,那能自动订阅上。

offset的保存

        一个消费组消费partition,需要保存offset记录消费到哪,以前保存在zk中,由于zk的写性能不好,以前的解决方法都是consumer每隔一分钟上报一次。这里zk的性能严重影响了消费的速度,而且很容易出现重复消费。

        在0.10版本后,kafka把这个offset的保存,从zk总剥离,保存在一个名叫__consumeroffsets topic的topic中。写进消息的key由groupid、topic、partition组成,value是偏移量offset。topic配置的清理策略是compact。总是保留最新的key,其余删掉。一般情况下,每个key的offset都是缓存在内存中,查询的时候不用遍历partition,如果没有缓存,第一次就会遍历partition建立缓存,然后查询返回。

确定consumer group位移信息写入__consumers_offsets的哪个partition,具体计算公式:

__consumers_offsets partition = Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount)         //groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定,默认是50个分区。

分配partition--reblance

生产过程中broker要分配partition,消费过程这里,也要分配partition给消费者。类似broker中选了一个controller出来,消费也要从broker中选一个coordinator,用于分配partition

下面从顶向下,分别阐述一下

  1. 怎么选coordinator。
  2. 交互流程。
  3. reblance的流程。

选coordinator

  1. 看offset保存在那个partition
  2. 该partition leader所在的broker就是被选定的coordinator

这里我们可以看到,consumer group的coordinator,和保存consumer group offset的partition leader是同一台机器。

交互流程

把coordinator选出来之后,就是要分配了

整个流程是这样的:

  1. consumer启动、或者coordinator宕机了,consumer会任意请求一个broker,发送ConsumerMetadataRequest请求,broker会按照上面说的方法,选出这个consumer对应coordinator的地址。
  2. consumer 发送heartbeat请求给coordinator,返回IllegalGeneration的话,就说明consumer的信息是旧的了,需要重新加入进来,进行reblance。返回成功,那么consumer就从上次分配的partition中继续执行。

reblance流程

  1. consumer给coordinator发送JoinGroupRequest请求。
  2. 这时其他consumer发heartbeat请求过来时,coordinator会告诉他们,要reblance了。
  3. 其他consumer发送JoinGroupRequest请求。
  4. 所有记录在册的consumer都发了JoinGroupRequest请求之后,coordinator就会在这里consumer中随便选一个leader。然后回JoinGroupRespone,这会告诉consumer你是follower还是leader,对于leader,还会把follower的信息带给它,让它根据这些信息去分配partition

        5、consumer向coordinator发送SyncGroupRequest,其中leader的SyncGroupRequest会包含分配的情况。

        6、coordinator回包,把分配的情况告诉consumer,包括leader。

当partition或者消费者的数量发生变化时,都得进行reblance。

列举一下会reblance的情况:

  1. 增加partition
  2. 增加消费者
  3. 消费者主动关闭
  4. 消费者宕机了
  5. coordinator自己也宕机了

kafka支持3种消息投递语义

At most once:最多一次,消息可能会丢失,但不会重复

At least once:最少一次,消息不会丢失,可能会重复

Exactly once:只且一次,消息不丢失不重复,只且消费一次(0.11中实现,仅限于下游也是kafka)

在业务中,常常都是使用At least once的模型,如果需要可重入的话,往往是业务自己实现。

At least once

先获取数据,再进行业务处理,业务处理成功后commit offset。

1、生产者生产消息异常,消息是否成功写入不确定,重做,可能写入重复的消息

2、消费者处理消息,业务处理成功后,更新offset失败,消费者重启的话,会重复消费

At most once

先获取数据,再commit offset,最后进行业务处理。

1、生产者生产消息异常,不管,生产下一个消息,消息就丢了

2、消费者处理消息,先更新offset,再做业务处理,做业务处理失败,消费者重启,消息就丢了

Exactly once

思路是这样的,首先要保证消息不丢,再去保证不重复。

  1. 生产者重做导致重复写入消息----生产保证幂等性
  2. 消费者重复消费---消灭重复消费,或者业务接口保证幂等性重复消费也没问题

由于业务接口是否幂等,不是kafka能保证的,所以kafka这里提供的exactly once是有限制的,消费者的下游也必须是kafka。所以一下讨论的,没特殊说明,消费者的下游系统都是kafka(注:使用kafka conector,它对部分系统做了适配,实现了exactly once)。

kafka(注:使用kafka conector,它对部分系统做了适配,实现了exactly once)。

生产者幂等性好做,没啥问题。

解决重复消费有两个方法:

  1. 下游系统保证幂等性,重复消费也不会导致多条记录。
  2. 把commit offset和业务处理绑定成一个事务。

本来exactly once实现第1点就ok了。

        但是在一些使用场景下,我们的数据源可能是多个topic,处理后输出到多个topic,这时我们会希望输出时要么全部成功,要么全部失败。这就需要实现事务性。既然要做事务,那么干脆把重复消费的问题从根源上解决,把commit offset和输出到其他topic绑定成一个事务。

<think>好的,我现在需要处理用户关于Kafka消费者消费策略的询问。首先,我得回忆一下Kafka的消费策略有哪些。根据之前的知识,Kafka主要有种分区分配策略:RangeAssignor、RoundRobinAssignor和StickyAssignor。不过,我需要确认这些信息是否正确,并且是否有最新的更新。用户给出的引用内容提到了消费者、分区分配策略以及Rebalance机制,这和我已有的知识是一致的。引用[2]中提到了消费者内的每个消费者负责不同分区,这说明分区的分配策略是关键。用户现在想详细了解这种策略,所以需要逐一解释每个策略的工作原理、优缺点以及适用场景。接下来,我需要确保每个策略的描述准确。例如,RangeAssignor是按主题的分区范围分配给消费者,可能导致不均衡的问题。而RoundRobin则是轮询分配,更均匀,但可能忽略订阅差异。StickyAssignor则是在保证均衡的同时尽量减少Rebalance时的变动。这些点需要明确,并且用例子说明。另外,用户可能对如何配置这些策略感兴趣,所以应该提到配置参数partition.assignment.strategy,并给出代码示例或者配置示例。但根据用户提供的示例,他们可能希望有类似Python代码的展示,但Kafka的配置通常是Java属性,所以可能需要用配置片段来说明。 还要注意引用对应的参考资料。用户提供的引用[2]和[3]涉及到分区分配和Rebalance,因此需要在适当的地方标注引用,比如在讨论分配策略时引用[2],在讨论Rebalance时引用[3]。需要检查是否有遗漏的策略,或者是否有其他策略如CooperativeStickyAssignor,但根据用户的问题,明确种,所以可能指的是传统的种。需要确认StickyAssignor是否是官方的一部分,或者是否有其他名称。最后,生成相关问题时要围绕这种策略展开,比如比较不同策略、配置方法、性能影响等,确保问题有助于用户进一步理解。</think>### Kafka消费者消费策略详解 Kafka消费者的分区分配策略决定了消费者如何分配主题分区,直接影响负载均衡和系统吞吐量。以下是种核心策略的对比分析: #### 一、RangeAssignor(范围分配策略) **算法原理**: 1. 按字典序排列主题消费者 2. 计算每个消费者分配的分区数: $$ \text{分区数} = \lceil \frac{\text{总分区数}}{\text{消费者数}} \rceil $$ 3. 将连续的分区段分配给消费者 **示例**: 主题A有5个分区,3个消费者时分配结果: - 消费者1:分区0,1 - 消费者2:分区2,3 - 消费者3:分区4 **优点**: - 实现简单 - 保证同一消费者处理连续数据 **缺点**: - 容易产生负载不均衡[^2] - 订阅主题时加剧不均衡 #### 二、RoundRobinAssignor(轮询分配策略) **算法原理**: 1. 将所有主题分区按哈希值排序 2. 循环遍历消费者进行分配 **示例**: 3个消费者分配5个分区: - 消费者1:分区0,3 - 消费者2:分区1,4 - 消费者3:分区2 **优点**: - 跨主题负载均衡 - 资源利用率高 **缺点**: - 消费者订阅不同主题时失效 - 不支持动态订阅变化[^2] #### 、StickyAssignor(粘性分配策略) **算法原理**: 1. 初始分配采用轮询方式 2. Rebalance时保留至少50%原分配 3. 通过贪心算法优化均衡度 **数学表达**: $$ \text{优化目标} = \min(\sum_{c \in C} |P_c - \overline{P}|) $$ 其中$P_c$为消费者c的分区数,$\overline{P}$为平均值 **优点**: - 减少Rebalance数据迁移[^3] - 自动平衡分区分配 - 支持渐进式扩容 **缺点**: - 算法复杂度较高 - 需要额外状态跟踪 #### 策略配置方法 ```java // 消费者配置示例 props.put("partition.assignment.strategy", "org.apache.kafka.clients.consumer.RangeAssignor,org.apache.kafka.clients.consumer.StickyAssignor"); ``` #### 性能对比 | 策略 | Rebalance成本 | 均衡度 | 扩展性 | |--------------|---------------|--------|--------| | Range | 低 | 差 | 差 | | RoundRobin | 中 | 优 | 良 | | Sticky | 高 | 优 | 优 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值