image

kafka从简到深入理解01

Kafka详解 - 忧愁的chafry - 博客园
Kafka 介绍_刘李404not found的博客-CSDN博客

[[使用消息队列的 10 个理由]]
详细讲解Docker-Compose部署Kafka KRaft集群环境 - 乐耶园

前言

  1. 理解Kafka的相关概念;
  2. 掌握Kafka的基本API使用;
  3. 了解Kafka的背后原理。
  4. [[008-字典卡片/dict/详细解释下 Kafka 系统中的控制器角色]]
  5. [[kafka-KRaft和zookeeper模式]]
  6. [[4.Archives/Archives-old-20240830/000-index/000-2-index/Apache kafka]]

首先Kafka是什么。

Kafka起初是由LinkedIn公司采用Scala语言开发的一个多分区、多副本且基于ZooKeeper协调的分布式消息系统,现已被捐献给Apache基金会。目前Kafka已经定位为一个分布式流式处理平台,它以高吞吐、可持久化、可水平扩展、支持流数据处理等多种特性而被广泛使用。

从上述介绍中,我们可以知道Kafka具有消息系统流式处理平台两种角色。为了更好的理解Kafka,本文将对消息系统进行介绍。

消息系统

消息系统,又被称作消息中间件。现在听到较多的是消息队列(MQ)的叫法,算是消息中间件的一种简称,其实都是同样的意思。那么消息系统是什么。

看一个我们都熟悉的场景——电子邮件。我们发送电子邮件,实际上就是将一个邮件文件从我们的电脑转发到对方电脑上,但是我们在发送的时候,并不需要关心对方的电脑是否开着,只管发送就好,邮件会先被发送到邮件服务器上,然后当对方电脑开机时,再从邮件服务器上获取邮件。邮件服务器就是一个消息系统,可暂存应用之间通信所发送的消息。而这样能带来的好处也显而易见了,作为发送消息的生产者并不需要关心接收消息的消费者的状态,生产者只需确保将消息成功发送到消息系统即可,这是一种异步通信模式

这种通信模式起到了解耦的作用,减少了生产者的职责。生产者只需关注生产消息和把消息发送到消息系统,而消费情况无需关注。

不仅如此,除上述我们描述的点对点(单消费者)情况,我们还可以在生产者无感知的情况下,使用发布/订阅模式。加入的新消费者去订阅主题,然后由消息系统广播给所有订阅的消费者,这为系统的扩展提供了便利。

例如一个下单操作,需要涉及优惠券、积分和短信等系统的处理,如果使用同步则需要等所有系统都处理完,但这样下单系统的响应时间将大大增加。通过使用消息系统,下单系统只需将下单操作的消息写入,然后完成下单操作,响应给用户。至于优惠券、积分、短信等将由相应系统从消息系统中获取下单操作消息进行处理。

我们再试想下这样的场景,当下单系统接收的请求突增的时候,消息系统也能起到削峰/限流的作用,暂存消息,让下游系统根据自身处理能力来处理消息,避免下游系统崩溃,系统也将更为稳定。

关注的问题

通过上述的介绍,对消息系统有了一定的认识。下面我们再进一步的思考下,消息系统的功能我们已经知道了,如果让我们使用一个消息系统,需要关注哪些问题,以下是我所想到的一些:

  1. 可用性。如果消息系统挂了,那消费的下游系统都将失效,所以需要保证可用性。
  2. 吞吐量。如果上游系统每秒百万级的吞吐量,需要让消息系统的写入吞吐量与其匹配。同时也需关注下游系统消费情况的吞吐量。
  3. 消息丢失。上游系统->消息系统->下游系统,这两个过程都有可能发生消息丢失。
  4. 消息顺序。这个问题其实和消息丢失是同时存在的,由于消息的丢失,将造成消息顺序的错乱。

Kafka中的基本概念

在消息系统的使用场景中有三种角色分别是生产者消息系统消费者,其中生产者负责产生消息和发送消息到消息系统,而消息系统将为消费者提供消息用于处理,如下图。

Kafka是基于发布/订阅模式的消息系统,如下图。生产者会将消息推送到Kafka中的某个Topic上,引入Topic的目的则是为了对消息进行分类,这样消费者就可以根据需要订阅相应的Topic获取消息

消息进行分类 Topic

解决单点问题 Broker

单点问题: 单节点服务出现宕机时,数据丢失和服务不可用问题。

  • broker: 一个kafka实例概念: 多个broker组成 kafka集群
  • zookeeper: 集群需要zooker做分布式协调: 选举Leader
  • Topic副本: Follower副本,分布到多个broker中

虽然Kafka这样已经能开始工作了,但紧接着又面临单点问题。而为了解决单点问题,Kafka引入了Broker的概念。一个Broker是一个Kafka实例,而一台机器上可运行多个Broker,这里我们认为一台机器上只有一个Kafka实例。多个Broker将形成一个Kafka集群,而Topic也可指定副本数量,作为多个副本位于多台机器上。

Kafka使用ZooKeeper在多个副本中选举出一个Leader,其他副本将作为Follower。

Leader主要负责读写消息,也就是和生产者、消费者打交道,同时将消息同步写到其他副本中。当有Broker失效时,如果Topic没有了Leader,则会重新选举出新的Leader,从而解决单点问题。

解决性能问题 Partition & Consumer-Group

个人理解: Partition分区可以时同一个 logic Topic分类下,分散到不同broker中分布式存储。
就可以使用不同broker宿主机提高性能

引入Broker和副本后解决了单点问题,接着面对的是性能问题,对于单个Topic来说,只有Leader所在的Broker与生产者、消费者进行通信,这样吞吐量将受到Broker所在的机器限制。那么如何提高吞吐量。Kafka将Topic拆分成多个分区,也就是将消息进行划分,类似数据库的分库,这样起到了负载均衡的作用,可不受单机的限制。如下图,生产者A分别往TopicA的分区0和分区1写消息,而消费者A、B则也从分区0、1获取消息。这里注意下,在不同分区存储的消息也是不同的,和副本的概念要分清楚。

从上图中我们可看到消费者A在消费TopicA时分别从分区0、分区1中获取消息,为了进一步提高吞吐量,Kafka引入了消费组的概念,将消费者A拆分成多个消费者,从而形成一个消费组。我们可以这样理解,消费者A是一个应用A实例,为了提高消费的吞吐量,我们多部署了几个消费者A实例,这样就有多个消费者形成一个消费组,但干的都是应用A做的事,需要与消费者B(不同的应用)区分开。

NOTE: 一般 设置消费组的消费者数与分区数一致 ,这是为了一个消费者能负责一个分区,提高效率。如果消费组的消费者数量小于分区数,则会出现一个消费者负责多个分区。而如果消费组的消费者数量大于分区数,则会出现有消费者分不到分区,造成浪费。所以一般保持一致。为了简洁,且消费组B和消费组A类似,所以下图未将消费组B画出。

Kafka中的基本概念就是以上这些:生产者、消费者、Topic、Broker、副本、分区和消息组。最后为了大家更好的理解分区的概念,再画一张细节图。

一个分区可以看做是一个单独的队列

title: 重要
生产者根据策略将消息写入对应的分区,
策略有三种:
1. 一、直接指定分区;
2. 二、如果未指定分区,则根据消息的key,通过`哈希函数`指定分区;
3. 三,如果没有key,则`轮询分区`。这里想强调的是分区中的数据是不同的,一条消息只会进入一个分区。而消费组中的消费者则会根据偏移量去分区中取得相应的消息进行消费处理。

kafka架构

Kafka的应用场景

Kafka 有多种应用场景,包括日志收集、消息系统、用户活动跟踪、运营指标收集以及流式处理等。

  • 日志收集:公司可以用 Kafka 收集各种服务的日志,以统一接口服务的方式开放给 Hadoop、HBase、Solr 等进行处理。
  • 消息系统:解耦生产者和消费者,起到缓存消息等作用。
  • 用户活动跟踪:记录 web 用户或 app 用户的各种活动,如浏览网页、搜索、点击等,这些活动信息被发布到 Kafka 的 topic 中,供订阅者进行实时监控分析或离线分析挖掘。
  • 运营指标:记录运营监控数据,包括收集各种分布式应用的数据,生产集中反馈,如报警和报告等。
  • 流式处理:如与 spark streaming 和 storm 等流式处理框架结合使用。

术语概念名词

名称 解释
Broker 消息中间件处理节点,一个Kafka节点就是一个broker,一个或者多个Broker可以组成一个Kafka集群
Topic Kafka根据topic对消息进行归类,发布到Kafka集群的每条消息都需要指定一个topic
Producer 消息生产者,向Broker发送消息的客户端
Consumer 消息消费者,从Broker读取消息的客户端
ConsumerGroup 每个Consumer属于一个特定的Consumer Group,一条消息可以被多个不同的Consumer Group消费,但是一个Consumer Group中只能有一个Consumer能够消费该消息
Partition 物理上的概念,一个topic可以分为多个partition,每个partition内部消息是有序的

服务端(brokers)和客户端(producer、consumer)之间通信通过TCP协议来完成。

[[kafka术语名词解释说明]]

下面给出 Kafka 一些重要概念,让大家对 Kafka 有个整体的认识和感知,后面还会详细的解析每一个概念的作用以及更深入的原理。

概念 描述
Producer 消息生产者,向 Kafka Broker 发消息的客户端。
Consumer 消息消费者,从 Kafka Broker 取消息的客户端。
Consumer Group 消费者组,组内每个消费者负责消费不同分区的数据,提高消费能力。一个分区只能由组内一个消费者消费,消费者组之间互不影响。
Broker 一台 Kafka 机器,一个集群由多个 broker 组成,一个 broker 可以容纳多个 topic。
Topic 可理解为一个队列,将消息分类,生产者和消费者面向同一个 topic。
Partition 为实现扩展性和提高并发能力,一个大 topic 可分布到多个 broker 上,一个 topic 可分为多个 partition,每个 partition 是一个有序的队列。
Replica 副本,为实现备份功能,保证节点故障时数据不丢失,一个 topic 的每个分区有若干副本,一个 leader 和若干 follower。
Leader 每个分区多个副本的 “主” 副本,生产者发送数据和消费者消费数据的对象。
Follower 每个分区多个副本的 “从” 副本,实时从 leader 同步数据,leader 发生故障时,某个 follower 会成为新的 leader。
offset 消费者消费的位置信息,监控数据消费位置,消费者挂掉重新恢复时可从该位置继续消费。
Zookeeper Kafka 集群正常工作依赖于 zookeeper,帮助存储和管理集群信息。
分布式流平台

Kafka集群将 Record 流存储在称为 topic 的类别中,每个记录由一个键、一个值和一个时间戳组成。Kafka 是一个分布式流平台,这到底是什么意思?

  • 发布和订阅记录流,类似于消息队列或企业消息传递系统。
  • 以容错的持久方式存储记录流。
  • 处理记录流。

存储机制

一、问题
生产者生产的消息不断追加到 log 文件末尾,可能导致 log 文件过大,进而使数据定位效率低下。
二、解决方案
Kafka 采取分片和索引机制,将每个 partition 分为多个 segment,每个 segment 对应 “.index” 索引文件和 “.log” 数据文件,这些文件位于以 topic 名 - 分区号命名的文件夹下。通过这种方式,提高数据定位效率,同时方便管理和存储数据。

topic 是逻辑上的概念,而 partition 是物理上的概念,每个 partition 对应于一个 log 文件,该 log 文件中存储的就是 Producer 生产的数据。Producer 生产的数据会不断追加到该 log 文件末端,且每条数据都有自己的 offset。消费者组中的每个消费者,都会实时记录自己消费到了哪个 offset,以便出错恢复时,从上次的位置继续消费。

由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据定位效率低下,Kafka 采取了分片索引机制,将每个 partition 分为多个 segment,每个 segment 对应两个文件:“.index” 索引文件和 “.log” 数据文件。这些文件位于同一文件下,该文件夹的命名规则为:topic 名-分区号。例如,first 这个 topic 有三分分区,则其对应的文件夹为 first-0,first-1,first-2。

# ls /root/data/kafka/first-0        
00000000000000009014.index    
00000000000000009014.log
00000000000000009014.timeindex
00000000000000009014.snapshot   
leader-epoch-checkpoint

index 和 log 文件以当前 segment 的第一条消息的 offset 命名。下图为 index 文件 和 log 文件的结构示意图。“.index” 文件存储大量的索引信息,“.log” 文件存储大量的数据,索引文件中的元数据指向对应数据文件中 message 的物理偏移量。

生产者

分区策略

分区原因
一、方便在集群中扩展

  1. 每个 partition 可以独立地调整以适应它所在的机器,实现灵活的资源分配。例如,如果某个节点的资源紧张,可以将一些分区迁移到资源更充足的节点上,而不会影响整个主题的运行。
  2. 多个 partition 组成一个 topic,使得在集群规模扩大时,可以将 topic 分布到更多的节点上,从而提高整个系统的存储和处理能力。
    二、提高并发能力
  3. 可以以 partition 为单位进行读写操作,多个消费者可以同时从不同的分区读取数据,实现并行处理,从而提高系统的吞吐量。
  4. 生产者也可以同时向不同的分区写入数据,充分利用集群的带宽和处理能力,避免单一节点成为瓶颈。

分区原则

我们需要将 Producer 发送的数据封装成一个 ProducerRecord 对象。该对象需要指定一些参数:

  • topic:string 类型,NotNull
  • partition:int 类型,可选
  • timestamp:long 类型,可选
  • key:string类型,可选
  • value:string 类型,可选 // message
  • headers:array 类型,Nullable
    (1) 指明 partition 的情况下,直接将给定的 partition 作为 partition 的值。
    (2) 没有指明 partition 但有 key 的情况下,将 key 的 hash 值与分区数取余得到 partition 值。
    (3) 既没有 partition 有没有 key 的情况下,第一次调用时随机生成一个整数(后面每次调用都在这个整数上自增),将这个值与可用的分区数取余,得到 partition 值,也就是常说的 round-robin 轮询算法。

数据可靠性保证

为保证 producer 发送的数据,能可靠地发送到指定的 topic,topic 的每个 partition 收到 producer 发送的数据后,都需要向 producer 发送 ack(acknowledge 确认收到),如果 producer 收到 ack,就会进行下一轮的发送,否则重新发送数据。

副本数据同步策略
(1)何时发送 ack?
确保有 follower 与 leader 同步完成,leader 再发送 ack,这样才能保证 leader 挂掉之后,能在 follower 中选举出新的 leader 而不丢数据。
(2)多少个 follower 同步完成后发送 ack?
全部 follower 同步完成,再发送 ack。

ISR

采用第二种方案,所有 follower 完成同步,producer 才能继续发送数据,设想有一个 follower 因为某种原因出现故障,那 leader 就要一直等到它完成同步。这个问题怎么解决? leader维护了一个动态的 in-sync replica set( ISR ):和 leader 保持同步的 follower 集合。当 ISR 集合中的 follower 完成数据的同步之后,leader 就会给 follower 发送 ack。如果 follower 长时间未向 leader 同步数据,则该 follower 将被踢出 ISR 集合,该时间阈值由 replica.lag.time.max.ms 参数设定。
leader 发生故障后,就会从 ISR 中选举出新的 leader

对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等 ISR 中的 follower 全部接受成功。 所以 Kafka 为用户提供了三种可靠性级别,用户根据可靠性和延迟的要求进行权衡,选择以下的配置。

ack 应答机制

对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等 ISR 中的 follower 全部接受成功。 所以 Kafka 为用户提供了三种可靠性级别,用户根据可靠性和延迟的要求进行权衡,选择以下的配置。
(1)ack 参数配置:

  • 0:producer 不等待 broker 的 ack,这提供了最低延迟,broker 一收到数据还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据。
  • 1:producer 等待 broker 的 ack,partition 的 leader 落盘成功后返回 ack,如果在 follower 同步成功之前 leader 故障,那么将会丢失数据。
  • -1(all):producer 等待 broker 的 ack,partition 的 leader 和 follower 全部落盘成功后才返回 ack。但是在 broker 发送 ack 时,leader 发生故障,则会造成数据重复。

故障处理细节

在这里插入图片描述

LEO:每个副本最大的 offset。 HW:消费者能见到的最大的 offset,ISR 队列中最小的 LEO。

(1)Follower 故障

follower 发生故障后会被临时踢出 ISR 集合,待该 follower 恢复后,follower 会 读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 leader 进行同步数据操作。等该 follower 的 LEO 大于等于该 partition 的 HW,即 follower 追上 leader 后,就可以重新加入 ISR 了。

(2)Leader 故障

leader 发生故障后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性,其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader 同步数据。
注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。

5.3 Exactly Once 语义

将服务器的 ACK 级别设置为-1,可以保证 producer 到 server 之间不会丢失数据,即 At Least Once 语义。相对的,将服务器 ACK 级别设置为0,可以保证生产者每条消息只会被发送一次,即At Most Once 语义。 At Least Once 可以保证数据不丢失,但是不能保证数据不重复;相对的,At Most Once 可以保证数据不重复,但是不能保证数据不丢失。

但是,对于一些非常重要的信息,比如交易数据,下游数据消费者要求数据既不重复也不丢失,即 Exactly Once 语义。 0.11版本的 Kafka,引入了幂等性:producer 不论向 server 发送多少重复数据,server 端都只会持久化一条。即:

At Least Once + 幂等性 = Exactly Once 

要启用幂等性,只需要将 producer 的参数中 enable.idompotence 设置为 true 即可。开启幂等性的 producer 在初始化时会被分配一个 PID,发往同一 partition 的消息会附带 Sequence Number。而 borker 端会对 <PID,Partition,SeqNumber> 做缓存,当具有相同主键的消息提交时,broker 只会持久化一条。

但是 PID 重启后就会变化,同时不同的 partition 也具有不同主键,所以幂等性无法保证跨分区会话的 Exactly Once。

消费者

消费方式 pull和push模式的区别

consumer 采用 pull(拉取)模式从 broker 中读取数据。
consumer 采用 push(推送)模式,broker 给 consumer 推送消息的速率是由 broker 决定的,很难适应消费速率不同的消费者。
它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,
典型的表现就是拒绝服务以及网络拥塞。

而 pull 模式则可以根据 consumer 的消费能力以适当的速率消费消息。
pull 模式不足之处是,如果 Kafka 没有数据,消费者可能会陷入循环中,一直返回空数据。因为消费者从 broker 主动拉取数据,需要维护一个长轮询,针对这一点, Kafka 的消费者在消费数据时会传入一个时长参数 timeout,如果当前没有数据可供消费,consumer 会等待一段时间之后再返回,这段时长即为 timeout。

push还是pull?

谁来进行消息控制执行逻辑?在消息服务中,还是客户端中。
在消息服务中,就要控制所有消息的发送,接收成功状态等所有控制和维护,客户端就处理
– partition push
: 服务端:我不知道你能打多少,所有人都推给你?
客户端: 太多了,打不过,我要死了?
– 客户端pull : partition
客户端: 我要打10个试试?
服务端:给你发了10个?
客户端: 10个太少,给我100个?
服务端:好嘞,100个已到账,注意查收。

上文提到的消息队列,大多是针对push模型的设计。现在市面上有很多经典的也比较成熟的pull模型的消息队列,如Kafka、MetaQ等。这跟JMS中传统的push方式有很大的区别,可谓另辟蹊径。 我们简要分析下push和pull模型各自存在的利弊。

| 模型      | 优点                    | 缺点                                         |
| ------- | --------------------- | ------------------------------------------ |
| Pull 模型 | 灵活性高、便于控制消费速率、消费者自主控制 | 可能存在`数据延迟和盲等`、实现相对复杂,方便顺序消息                |
| Push 模型 | 实时性较好、实现简单            | 难以适应不同的消费能力、可能导致消费者过载、`慢消费`无疑是push模型最大的致命伤 |

慢消费

慢消费无疑是push模型最大的致命伤,穿成流水线来看,如果消费者的速度比发送者的速度慢很多,势必造成消息在broker的堆积。假设这些消息都是有用的无法丢弃的,消息就要一直在broker端保存。当然这还不是最致命的,最致命的是broker给consumer推送一堆consumer无法处理的消息,consumer不是reject就是error,然后来回踢皮球。 反观pull模式,consumer可以按需消费,不用担心自己处理不了的消息来骚扰自己,而broker堆积消息也会相对简单,无需记录每一个要发送消息的状态,只需要维护所有消息的队列和偏移量就可以了。所以对于建立索引等慢消费,消息量有限且到来的速度不均匀的情况,pull模式比较合适。

消息延迟与忙等

这是pull模式最大的短板。由于主动权在消费方,消费方无法准确地决定何时去拉取最新的消息。如果一次pull取到消息了还可以继续去pull,如果没有pull取到则需要等待一段时间重新pull。 但等待多久就很难判定了。你可能会说,我可以有xx动态pull取时间调整算法,但问题的本质在于,有没有消息到来这件事情决定权不在消费方。也许1分钟内连续来了1000条消息,然后半个小时没有新消息产生, 可能你的算法算出下次最有可能到来的时间点是31分钟之后,或者60分钟之后,结果下条消息10分钟后到了,是不是很让人沮丧? 当然也不是说延迟就没有解决方案了,业界较成熟的做法是从短时间开始(不会对broker有太大负担),然后指数级增长等待。比如开始等5ms,然后10ms,然后20ms,然后40ms……直到有消息到来,然后再回到5ms。 即使这样,依然存在延迟问题:假设40ms到80ms之间的50ms消息到来,消息就延迟了30ms,而且对于半个小时来一次的消息,这些开销就是白白浪费的。 在阿里的RocketMq里,有一种优化的做法-长轮询,来平衡推拉模型各自的缺点。基本思路是:消费者如果尝试拉取失败,不是直接return,而是把连接挂在那里wait,服务端如果有新的消息到来,把连接notify起来,这也是不错的思路。但海量的长连接block对系统的开销还是不容小觑的,还是要合理的评估时间间隔,给wait加一个时间上限比较好~

解释:“消息延迟与忙等” 指的是在信息传递过程中出现的两种情况。“消息延迟” 表示消息从发送方发出到接收方接收之间存在时间上的滞后;“忙等” 则是指在等待某个条件满足时,持续占用资源进行等待而不做其他有效操作。

更细致地解释,“消息延迟” 可能由网络拥堵、服务器处理能力不足、传输距离等多种因素导致,使得消息不能及时到达目的地。而 “忙等” 通常是一种不太高效的等待方式,会浪费系统资源,影响整体性能。

顺序消息

如果push模式的消息队列,支持分区,单分区只支持一个消费者消费,并且消费者只有确认一个消息消费后才能push送另外一个消息,还要发送者保证全局顺序唯一,听起来也能做顺序消息,但成本太高了,尤其是必须每个消息消费确认后才能发下一条消息,这对于本身堆积能力和慢消费就是瓶颈的push模式的消息队列,简直是一场灾难。 反观pull模式,如果想做到全局顺序消息,就相对容易很多:

  1. producer对应partition,并且单线程。
  2. consumer对应partition,消费确认(或批量确认),继续消费即可。

所以对于日志push送这种最好全局有序,但允许出现小误差的场景,pull模式非常合适。如果你不想看到通篇乱套的日志~~ Anyway,需要顺序消息的场景还是比较有限的而且成本太高,请慎重考虑。

分区分配策略

一个 consumer group 中有多个 consumer,一个 topic 有多个 partition,所以必然会涉及到 partition 的分配问题,即确定哪个 partition 由哪个 consumer 来消费。 Kafka 有两种分配策略,
一个是 RoundRobin,
一个是 Range,
默认为range,
(1) RoundRobin

在这里插入图片描述

RoundRobin 轮询方式将分区所有作为一个整体进行 hash 排序,消费者组内分配分区个数最大差别为1,是按照组来分的,可以解决多个消费者消费数据不均衡的问题。

但是,当消费者组内订阅不同主题时,可能造成消费混乱,如下图所示,consumer0 订阅主题A,consumer1 订阅主题B,将 A、B主题的分区排序后分配给消费者组,TopicB 分区中的数据可能分配到 consumer0 中。
在这里插入图片描述

当消费者组内消费者发生变化时,会触发分区分配策略(方法重新分配)

(2)Range

在这里插入图片描述

range 方式是按照主题来分的,不会产生轮询方式的消费混乱问题。

但是,如下图所示,consumer0、consumer1 同时订阅了主题A和B,可能造成消息分配不对等问题,当消费者组内订阅的主题越多,分区分配可能越不均衡。
在这里插入图片描述

知识点总结:
  1. Kafka 有两种分区分配策略:RoundRobin 和 Range。
  2. RoundRobin 轮询方式将分区整体 hash 排序后按组分配,能解决消费不均衡问题,但组内订阅不同主题时可能造成消费混乱,且组内消费者变化会触发重新分配。
  3. Range 方式按主题分配分区,不会产生消费混乱问题,但消费者同时订阅多个主题时可能造成消息分配不对等,且订阅主题越多,分区分配可能越不均衡。

消费顺序

【1】一个partition同一个时刻在一个consumer group中只能有一个consumer instance在消费,从而保证消费顺序。

【2】consumer group中的consumer instance的数量不能比一个Topic中的partition的数量多,否则,多出来的consumer消费不到消息。

【3】Kafka只在partition的范围内保证消息消费的局部顺序性,不能在同一个topic中的多个partition中保证总的消费顺序性。

【4】如果有在总体上保证消费顺序的需求,那么我们可以通过将topic的partition数量设置为1,将consumer group中的consumer instance数量也设置为1,但是这样会影响性能,所以kafka的顺序消费很少用。

offset 的维护

由于 consumer 在消费过程中可能会出现断电宕机等故障,consumer 恢复后,需要从故障前的位置继续消费,所以 consumer 需要实时记录自己消费到了哪个 offset,以便故障恢复后继续消费。 Kafka 0.9 版本之前,consumer 默认将 offset 保存在 Zookeeper 中,从 0.9 版本开始,consumer 默认将 offset 保存在 Kafka 一个内置的 topic 中,该 topic 为 __consumer_offsets。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐