Kafka(一)理论篇(概述、基本术语、工作原理与工作过程、消息路由、HW截断机制..)

1. 概述

1.1 kafaka 简介

Apache Kafka 是一个快速、可扩展的、高吞吐的、可容错的分布式“发布-订阅”消息系统,使用 Scala 与 Java 语言编写,能够将消息从一个端点传递到另一个端点,较之传统的消息中间件(例如 ActiveMQ、RabbitMQ),Kafka 具有高吞吐量、内置分区、支持消息副本和高容错的特性,非常适合大规模消息处理应用程序。

Kafka 官网: http://kafka.apache.org/

1.2 Kafa 系统架构

老版架构图:
在这里插入图片描述
新版架构图:

Kafka 在 0.9 之前是基于 Zookeeper 来存储 Partition 的 Offset 信息 (consumers/{group}/offsets/{topic}/{partition}),因为 Zookeeper 并不适用于频繁的写操作,所以在 0.9 之后通过内置 Topic 的方式来记录对应 Partition 的 Offset:

在这里插入图片描述

Kafka broker:就是Kafka主机
Producer:消息生产者
Consumer:消息消费者
Zookeeper Cluster:ZK集群,管理broker

如上图,一个kafka架构包括:

  • 若干个Producer(服务器日志、业务数据、web前端产生的page view等)
  • 若干个Broker(kafka支持水平扩展,一般broker数量越多集群的吞吐量越大)
  • 若干个consumer group
  • 一个Zookeeper集群(kafka通过Zookeeper管理集群配置、选举Broker Controller)。

1.3 应用场景

官网就有介绍,打开官网找到USE CASES:
在这里插入图片描述

  • Messaging - 消息系统

    • 最基本用法,生产者生产的没有处理的消息先缓存到Kafka里,后期进行逐步的处理,即生产和消费的速度不匹配的场景,限流削峰就是这种用法(类似于ActiveMQ、RabbitMQ)
    • 一般在秒杀业务经常用到,主要防止流量过大导致系统宕机,但会造成超卖的问题。
      在这里插入图片描述

    Kafka可以很好地替代传统邮件代理。消息代理的使用有多种原因(将处理与数据生产者分离,缓冲未处理的消息等)。与大多数邮件系统相比,Kafka具有更好的吞吐量,内置的分区,复制和容错能力,这使其成为大规模邮件处理应用程序的理想解决方案。

    根据我们的经验,消息传递的使用通常吞吐量较低,但是可能需要较低的端到端延迟,并且通常取决于Kafka提供的强大的持久性保证。

    在这一领域,Kafka与ActiveMQ或 RabbitMQ等传统消息传递系统相当。

  • Website Activity Tracking - Web站点活动追踪

    • 记录站点行为,收集数据,对用户行为进行分析,可以进行用户画像,精准营销
    • 用户在网站的不同活动消息发布到不同的主题中心,然后可以对这些消息进行实时监测实时处理。当然,也可加载到 Hadoop 或离线处理数据仓库,对用户进行画像。像淘宝、京东这些大型的电商平台,用户的所有活动都是要进行追踪的。

    Kafka最初的用例是能够将用户活动跟踪管道重建为一组实时的发布-订阅供稿。这意味着将网站活动(页面浏览,搜索或用户可能采取的其他操作)发布到中心主题,每种活动类型只有一个主题。这些提要可用于一系列用例的订阅,包括实时处理,实时监控,以及加载到Hadoop或脱机数据仓库系统中以进行脱机处理和报告。

    活动跟踪通常量很大,因为每个用户页面视图都会生成许多活动消息。

  • Metrics - 数据监控

    • 从分布式应用里收集指定类型的监控数据,聚合到Kafka里

    Kafka通常用于操作监控数据。这涉及汇总来自分布式应用程序的统计信息,以生成操作数据的集中供稿。

  • Log Aggregation - 日志聚合

    • 将应用服务器的日志文件收集到文件服务器,然后对文件进行清理,分类分主题写到Kafka(类似于Scribe或Flume)在这里插入图片描述

    许多人使用Kafka代替日志聚合解决方案。日志聚合通常从服务器上收集物理日志文件,并将它们放在中央位置(也许是文件服务器或HDFS)以进行处理。Kafka提取文件的详细信息,并以日志流的形式更清晰地抽象日志或事件数据。这允许较低延迟的处理,并更容易支持多个数据源和分布式数据消耗。与以日志为中心的系统(例如Scribe或Flume)相比,Kafka具有同样出色的性能,由于复制而提供的更强的耐用性保证以及更低的端到端延迟。

  • Stream Processiong - 流处理

    • 有点类似于工作流的感觉,一个业务细分为多个节点,每个节点等于一个主题,当前节点处理完成就发布到下一个节点的主题处理

    Kafka的许多用户在由多个阶段组成的处理管道中处理数据,其中原始输入数据从Kafka主题中使用,然后进行汇总,充实或以其他方式转换为新主题,以供进一步使用或后续处理。例如,用于推荐新闻文章的处理管道可能会从RSS提要中检索文章内容,并将其发布到“文章”主题中。进一步的处理可能会使该内容规范化或重复数据删除,并将清洗后的文章内容发布到新主题;最后的处理阶段可能会尝试向用户推荐此内容。这样的处理管道基于各个主题创建实时数据流图。从0.10.0.0开始,一个轻量但功能强大的流处理库称为Kafka Streams 可以在Apache Kafka中使用来执行上述数据处理。除了Kafka Streams,其他开源流处理工具还包括Apache Storm和 Apache Samza。

  • 事件源 Event Sourcing

    • 应用中的各种事件,每一种类型的事件都可以作为一个主题,事件很大的特征就是时间顺序,可以按照事件产生的时间先后顺序写入到Kafka,不同的事件写入到不同的主题

    事件源是一种应用程序设计方式,其中状态更改以时间顺序记录。Kafka对非常大的存储日志数据的支持使其成为使用这种样式构建的应用程序的绝佳后端。

  • Commit Log - 提交日志

    • 可以用作分布式系统的一种外部提交日志

    Kafka可以用作分布式系统的一种外部提交日志。该日志有助于在节点之间复制数据,并充当故障节点恢复其数据的重新同步机制。Kafka中的日志压缩功能有助于支持此用法。在这种用法中,Kafka类似于Apache BookKeeper项目。

PS:Kafka的定位个人感觉像一个数据/消息中转站,有人存,有人用。

1.4 kafka 高吞吐率实现

Kafka 与其它 MQ 相比,其最大的特点就是高吞吐率。为了增加存储能力,Kafka 将所有的消息都写入到了低速大容的硬盘。按理说,这将导致性能损失,但实际上,kafka 仍可保持超高的吞吐率,性能并未受到影响。其主要采用了如下的方式实现了高吞吐率。

  • 顺序读写:Kafka 将消息写入到了分区 partition 中,而分区中消息是顺序读写的。顺序读写要远快于随机读写。
  • 零拷贝:生产者、消费者对于 kafka 中消息的操作是采用零拷贝实现的。(直接操作内核空间)
  • 批量发送:Kafka 允许使用批量消息发送模式。(先把每次要发送的消息都放入缓存,根据不同的策略,比如缓存空间满了,在批量一起发送出去)
  • 消息压缩:Kafka 支持对消息集合进行压缩。(可以把一堆消息压缩成一个消息,这样传输次数、传输量都变少了,传输压力就变小了,当然压缩和解压的操作是在生产者和消费者端完成的,会增加生产者和消费者端的CPU工作量,但是对于大消息的处理,瓶颈主要集中在网络传输传输上而不是CPU,所以是值得的)

2. Kafka 基本术语

对于 Kafka 基本原理的介绍,可以通过对以下基本术语的介绍进行。

2.1 Topic

主题。在 Kafka 中,使用一个类别属性来划分消息的所属类,划分消息的这个类称为 topic。topic 相当于消息的分类标签,是一个逻辑概念。

2.2 Partition

分区。topic 中的消息被分割为一个或多个 partition,其是一个物理概念,对应到系统上就是一个或若干个目录。

一个 topic 可以包含多个 partition。每个 partition 都是一个 FIFO 队列,其中的消息是有序的。但 partition 间的消息是无序的。

在这里插入图片描述

发消息时若不指定partition,默认会轮询依次将消息放入每个分区。发消息时也可以为每条消息配一个key,根据key的hash值和partition数量取模,算出要放入的分区。

使用kafka 原生 API发送消息时可以指定主题、分区、key:
在这里插入图片描述
如果指定的分区不存在,会在用key算

2.3 segment

段。将 partition 进一步细分为了若干的 segment,每个 segment 文件的最大大小相等。(通常我们说segment文件指的都是.log文件,但实际上segment代表的是.log和.index、.timeindex一套文件

一个 partition 中会包含很多的 segment,每个 segment 中的消息数据在磁盘中是顺序存放的,但 segment 间不一定是顺序存放的。

在这里插入图片描述
消息数据存在.log文件,每个.log文件对应有一个.index索引文件
在这里插入图片描述
看到文件名由20位数字组成,表示的意思是当前segment之前有多少条消息
上图中170210.log表示当前这个segment文件之前有170210条消息
每个消息都有一个编号和偏移量offset,假如我们要消费170213消息
先会根据二分法在分区中所有的segment文件中先找到该消息在哪个segment文件
找到以后将消息编号减去segment的文件名编号,170213-170210=3
根据3再从对应的index文件中找到对应的偏移量 2 = 0348
0348就是该消息在.log文件中的位置,磁盘空间的位置

segment的意义:

每个分区可以存的数据量都是很大的,如果不分segment,意味着创建分区的时候需要在磁盘空间中找一个很大很大的连续空间,并且整个空间没有放任何东西,才能顺序存放,这个找起来会很困难,而将一个分区分成一个个小的segment空间,只要保证每个segment空间是连续的即可,segment之间无所谓。

segment空间大小可以通过参数配置:
在这里插入图片描述

2.4 Broker

在这里插入图片描述

Kafka 集群包含一个或多个服务器,每个服务器节点称为一个 broker。

假设某 topic 中有 N 个 partiiton,集群中有 M 个 broker,则 partition 与 broker 的数量关系为:

  • 若 N>M,且 N % M = 0,则每个 broker 会平均存储该 topic 的多个 partition。
  • 若 N>M,且 N % M != 0,则每个 broker 中的 partition 数量是不平均的。
  • 若 N<M,则会有 N 个 broker 中都存放了一个 partition,而有 M-N 个 broker 中是没有partition 的

2.5 Producer

生产者。即消息的发布者,其会将某 topic 的消息发布到相应的 partition 中。

2.6 Consumer

消费者。可以从 broker 中读取消息。

一个消费者可以消费多个 topic 的消息。
一个消费者也可以消费同一个 topic 中的多个 partition 中的消息。
一个 partition 允许多个无关消费者同时消费。

2.7 Consumer Group

consumer group 是 kafka 提供的可扩展且具有容错性的消费者机制。组内可以有多个消费者,它们共享一个公共的 ID,即 group ID。组内的所有消费者会协调在一起平均消费订阅主题的所有分区

Kafka 可以保证在稳定状态下,一个 partition 中的消息只能被同一个 consumer group 中的一个 consumer 消费,而一个组内 consumer 只会消费某一个或几个特定的 partition。当然,一个消息可以同时被多个 consumer group 消费。

组中 consumer 数量与 partition 数量的对应关系如下。

  • 说明的问题:一个消费者可以同时消费多个分区中的消息:
    在这里插入图片描述

  • 说明的问题:同组的多个消费者可以自动均分多个分区中的消息(组内成员不会重复消费)
    在这里插入图片描述

  • 说明的问题:同组的多个消费者可以自动均分多个分区中的消息
    在这里插入图片描述

  • 说明的问题:不可能出现同组的多个消费者消费同一个分区中的消息(组内成员不会重复消费)
    在这里插入图片描述

  • 说明的问题:不同组的各个组之间可以重复消费
    在这里插入图片描述

设计目的:对于开发来说简单,并且减少了通讯开销,所以不允许同组多个consumer同时消费一个partition,这样也保证了同组消费者之间不会重复消费


2.8 Replicas of partition

分区副本。副本是一个分区的备份,是为了防止消息丢失而创建的分区的备份。

--replication-factor用来指定副本数量,即副本因子
在这里插入图片描述
复制因子是不能超过broker数量的:
在这里插入图片描述

2.9 Partition Leader

每个 partition 有多个副本,其中有且仅有一个作为 Leader,Leader 是当前负责消息读写的 partition。即所有读写操作只能发生于 Leader 分区上

2.10 Partition Follower

所有 Follower 都需要从 Leader 同步消息,Follower 与 Leader 始终保持消息同步。

Leader 与 Follower 是主备关系,非主从。(主从,从是可以读的,主备只有主干活)

Partition Leader 是通过 Broker Controller 选举出来的。

2.11 ISR

  • ISR,In-Sync Replicas,是指副本同步列表
  • AR,Assigned Replicas,是指同一分区所有副本列表
  • OSR,Outof-Sync Replicas,退出同步的副本列表(当前副本所在主机挂了的情况,或者只要同步过程耗费的时间超过指定的允许时间范围内,则被认为同步失败,会将副本从ISR列表移到OSR列表)(逻辑概念)

ISR是由leader维护,follower从leader同步数据有一些延迟,超过相应的阈值会把 follower 剔除出 ISR, 存入OSR(Out-of-Sync Replicas )列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。

在这里插入图片描述
图中leader是2,代表分区0的Leader是brokerId为2的主机
isr则代表副本同步列表, 代表当前分区各个同步中的副本所在的主机的brokerId


Kafka可视化工具 https://www.kafkatool.com/download.html
在这里插入图片描述
在这里插入图片描述

2.12 offset

偏移量。每条消息都有一个当前 Partition 下唯一的 64 字节的 offset,它是相对于当前分区第一条消息的偏移量。

其实就相当于.log文件名上的编号
在这里插入图片描述

2.13 offset commit

Consumer 从 partition 中取出一批消息写入到 buffer 对其进行消费,在规定时间内消费完消息后,会自动将其消费消息的 offset 提交给 broker,以让 broker 记录下哪些消息是消费过的。当然,若在时限内没有消费完毕,其是不会提交 offset 的。

offset记录的其实就是下一次消费的时候要从哪开始消费,每个Consumer Group有自己的offset

2.14 Rebalance

当消费者组中消费者数量发生变化,或 Topic 中的 partition 数量发生了变化时,partition的所有权会在消费者间转移,即 partition 会重新分配,这个过程称为再均衡 Rebalance。

再均衡能够给消费者组及 broker 集群带来高可用性和伸缩性,Rebalance 发生时,Group 下所有 Consumer 实例都会协调在一起共同参与,Kafka 能够保证尽量达到最公平的分配。但是 Rebalance 过程对 Consumer Group 会造成比较严重的影响。在 Rebalance 的过程中 Consumer Group 下的所有消费者实例都会停止工作,等待 Rebalance 过程完成。因此要避免不必要的再均衡。

rebalance是由Group Coordinator负责的。


2.15 __consumer_offsets

消费者提交的 offset 被封装为了一种特殊的消息被写入到了一个由系统创建的、名称为__consumer_offset 的特殊主题的 partitions 中了。该 Topic 默认包含 50 个分区。

每个 Consumer Group 的消费的 offset 都会被记录在__consumer_offsets 主题的 partition中。该主题的 partition 默认有 50 个,那么 Consumer Group 消费的 offset 存放在哪个分区呢?其有计算公式:Math.abs(groupID.hashCode()) % 50。

__consumer_offsets 中的数据默认有效期为 1 天。

演示:
创建主题hk,3分区2副本,并创建一个生产者发送消息:
在这里插入图片描述

刷新Kafka可视化工具,可以看到数据
在这里插入图片描述

数据是byte格式
在这里插入图片描述
在这里插入图片描述

消费之前看下/tmp/kafka-logs目录:
在这里插入图片描述

创建一个消费者消费消息:
在这里插入图片描述
在这里插入图片描述

消费之后看下/tmp/kafka-logs目录:
在这里插入图片描述
系统默认会生成50个分区,1个备份,这里通过配置文件修改成3个备份,生产环境下一定要做副本

如何修改:
在这里插入图片描述
在这里插入图片描述

看一下__consumer_offsets中的数据:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.16 Broker Controller

Kafka 集群的多个 broker 中,有一个会被选举为 controller,负责管理整个集群中 partition和副本 replicas 的状态。partition leader 就是 broker controller 选举出来的。ISR 中的 follower采用的是轮流坐庄方式。

2.17 Zookeeper

Zookeeper 负责维护和协调 broker,负责 Broker Controller 的选举。(ZK应用场景之一,Leader选举,同时注册节点,谁注册上谁就是Controller)

在这里插入图片描述

2.18 Group Coordinator

group Coordinator (组协调者) 是运行在每个 broker 上的进程,主要用于 Consumer Group 中的各个成员的 offset 位移管理Rebalance。Group Coordinator 同时管理着当前 broker 的所有消费者组。

Group Coordinator 是一个服务,每个 Broker在启动的时候都会启动一个该服务。Group Coordinator 的作用是用来存储 Group 的相关 Meta 信息,并将对应 Partition 的 Offset 信息记录到 Kafka 内置Topic(__consumer_offsets) 中。Kafka 在 0.9 之前是基于 Zookeeper 来存储 Partition 的 Offset 信息 (consumers/{group}/offsets/{topic}/{partition}),因为 Zookeeper 并不适用于频繁的写操作,所以在 0.9 之后通过内置 Topic 的方式来记录对应 Partition 的 Offset。

每个 Group 都会选择一个 Coordinator 来完成自己组内各 Partition 的 Offset 信息,选择的规则如下:

  1. 计算 Group 对应在 __consumer_offsets 上的 Partition
  2. 根据对应的Partition寻找该Partition的leader所对应的Broker,该Broker上的Group Coordinator即就是该Group的Coordinator

Partition计算规则:

partition-Id(__consumer_offsets) = Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount)

其中 groupMetadataTopicPartitionCount 对应 offsets.topic.num.partitions 参数值,默认值是 50 个分区

Group Coordinator中有缓存记录 Consumer Group 的 offset,消费者消费的时候offset的查询不是从__consumer_offsets主题的segment文件,即物理磁盘中查询的,offset commit的时候也是先提交到Group Coordinator,由它处理

3. Kafka 工作原理与过程

3.1 消息路由策略

在通过 API 方式发布消息时,生产者是以 Record 为消息进行发布的。Record 中包含 key与 value,value 才是我们真正的消息本身,而 key 用于路由消息所要存放的 Partition。消息要写入到哪个 Partition 并不是随机的,而是有路由策略的。

  • 1) 若指定了 partition,则直接写入到指定的 partition;
  • 2) 若未指定 partition 但指定了 key,则通过对 key 的 hash 值与 partition 数量取模,该取模结果就是要选出的 partition 索引; (消费者提交的offset被封装成特殊消息写入__consumer_offsets这个特殊主题,放到哪个分区用的就是这种方式,key就是GroupID
  • 3) 若 partition 和 key 都未指定,则使用轮询算法选出一个 partition。

3.2 消息写入算法

消息生产者将消息发送给 broker,并形成最终的可供消费者消费的 log,是一个比较复杂的过程。

  • 1) producer 向 broker 集群提交连接请求,其所连接上的任意 broker 都会向其发送 broker controller 的通信 URL,即 broker controller 主机配置文件中的 listeners 地址
  • 2) 当 producer 指定了要生产消息的 topic 后,其会向 broker controller 发送请求,请求当前 topic 中所有 partition 的 leader 列表地址
  • 3) broker controller在接收到请求后,会从zk中查找到指定topic的所有partition的leader,并返回给 producer
  • 4) producer 在接收到 leader 列表地址后,根据消息路由策略找到当前要发送消息所要发送的 partition leader,然后将消息发送给该 leader
  • 5) leader 将消息写入本地 log,并通知 ISR 中的 followers
  • 6) ISR 中的 followers 从 leader 中同步消息后向 leader 发送 ACK
  • 7) leader 收到所有 ISR 中的 followers 的 ACK 后,增加 HW,表示消费者已经可以消费到该位置了
  • 8) 若 leader 在等待的 followers 的 ACK 超时了,发现还有 follower 没有发送 ACK,则会将该 follower 从 ISR 中清除,然后增加 HW。

3.3 HW 机制

HW,HighWatermark,高水位,表示 Consumer 可以消费到的最高 partition 偏移量。HW保证了 Kafka 集群中消息的一致性。确切地说,是在 broker 集群正常运转的状态下,保证了partition 的 Follower 与 Leader 间数据的一致性。

LEO,Log End Offset,日志最后消息的偏移量。消息是被写入到 Kafka 的日志文件中的,这是当前最后一个写入的消息在 Partition 中的偏移量。

对于 leader 新写入的消息,consumer 是不能立刻消费的。leader 会等待该消息被所有ISR 中的 partition follower 同步后才会更新 HW,此时消息才能被 consumer 消费。

动画演示:
下面是一个分区的3个副本,一开始LEO和HW都在3,消费者最多可以消费到3
在这里插入图片描述

现在开始发送三条数据,4,5,6,Leader每收到一条数据,LEO就会变化一次,最终指向6,此时Follower还没有同步数据:
在这里插入图片描述

慢慢的B和C开始同步数据,B收到了4和5,C性能比较差,暂时收到了4,他们对应的LEO也会变化:
在这里插入图片描述

因为大家都有4,所以HW就上涨到4,消费者最多可以消费到4
在这里插入图片描述

以此类推:
在这里插入图片描述

HW的变化取决于集群中性能最差的机器,木桶效应

3.4 HW 截断机制

如果 partition leader 接收到了新的消息, ISR 中其它 Follower 正在同步过程中,还未同步完毕时leader挂了。此时就需要选举出新的leader。若没有HW截断机制,将会导致partition中 leader 与 follower 数据的不一致。

动画演示 - 没有HW截断机制时所引发的数据不一致演示:
目前正在同步中:
在这里插入图片描述

突然Leader宕机了:
在这里插入图片描述

此时重新选举B为新的Leader,并且又来了新的数据:
在这里插入图片描述

follower C做同步,此时都还没有什么问题:
在这里插入图片描述

但是这个时候机器A又恢复了重新加入了集群:
在这里插入图片描述

A作为follower从LeaderB同步数据,但是之前已经有6了,直接同步7:
在这里插入图片描述

可以看到A的6号数据和B的6号数据不一致

动画演示 - 截断机制原理演示:
让机器A恢复的时候,将LEO恢复到宕机时HW的位置即可
在这里插入图片描述

然后重新从Leader同步:
在这里插入图片描述

HW 截断机制:宕机的机器恢复时,将LEO恢复到宕机时HW的位置,然后进行数据同步

和ZK同步原理差不多,ZK是先根据当前本地最大事务编号和leader相同事务编号的内容比较,如果内容不同,会将当前事务-1,再次和leader比较,一直递归判断,直到相同,然后从相同的事务编号开始从Leader同步数据

3.5 消息发送的可靠性机制

生产者向 kafka 发送消息时,可以选择需要的可靠性级别。通过 acks 参数的值进行设置。

(1) 0 值

异步发送。生产者向 kafka 发送消息而不需要 kafka 反馈成功 ack。该方式效率最高,但可靠性最低。其可能会存在消息丢失的情况。

(2) 1 值

同步发送,默认值。生产者发送消息给 kafka,broker 的 partition leader 在收到消息后马上发送成功 ack,生产者收到后才会再发送消息。如果一直未收到 kafka 的 ack,则生产者会认为消息发送失败,会重发消息。

该方式不能使 producer 确认其发送的消息是成功的,但可以确认消息发送失败。(即截断机制演示时Leader A 消息6丢失的情况)

(3) -1 值

同步发送。其值等同于 all。生产者发送消息给 kafka,kafka 收到消息后要等到 ISR 列表中的所有副本都同步消息完成后,才向生产者发送成功 ack。如果一直未收到 kafka 的 ack,则认为消息发送失败,会自动重发消息。

这种模式可靠性最高,很少出现消息丢失的情况(批量发送的时候缓存满了正准备发送还没发的时候,新的消息是写入不到缓存的,这个消息就会丢失,即消息从生产者端丢失的情况)。但可能会出现部分 Follower 重复接收消息的情况。(Leader挂了,收不到ack,选举后新的Leader可能已经同步过部分数据,然后生产者重新发送消息的情况)

如果kafka集群中Leader挂了,配1有可能引发消息丢失,配-1有可能引发消息重复接受

Kafka接收重复消息的问题,解决方案:生产者给消息绑定ID,消费的时候去重

3.6 消费者消费过程解析

生产者将消息发送到 topic 中,消费者即可对其进行消费,其消费过程如下:

  • 1) consumer 向 broker 集群提交连接请求,其所连接上的任意 broker 都会向其发送 broker controller 的通信 URL,即 broker controller 主机配置文件中的 listeners 地址
  • 2) 当 consumer 指定了要消费的 topic 后,其会向 broker controller 发送 poll 请求
  • 3) broker controller 会为 consumer 分配一个或几个 partition leader,并将该 partitioin 的当前 offset 发送给 consumer
  • 4) consumer 会按照 broker controller 分配的 partition 对其中的消息进行消费
  • 5) 当消费者消费完该条消息后,消费者会向 broker 发送一个该消息已被消费的反馈,即该消息的 offset
  • 6) 当 broker 接到消费者的 offset 后,会更新到相应的__consumer_offset 中
  • 7) 以上过程一直重复,直到消费者停止请求消息
  • 8) 消费者可以重置 offset,从而可以灵活消费存储在 broker 上的消息

同组消费者是如何保证不重复消费数据的?
因为同组消费者,一个分区只能被其中一个消费者消费。

3.7 Partition Leader 选举范围

当 leader 挂了后 broker controller 会从 ISR 中选一个 follower 成为新的 leader。但,若 ISR中的所有副本都挂了怎么办?可以通过 unclean.leader.election.enable 的取值来设置 Leader选举的范围。
在这里插入图片描述

(1) false

必须等待ISR列表中有副本活过来才进行新的选举。该策略可靠性有保证,但可用性低。

什么时候可以从OSR回到ISR,由Broker Controller完成,它会定期检测OSR的follower,判断是否符合进入ISR的条件,符合就会加进去,是个定时任务

(2) true

在 ISR 中没有副本的情况下可以选择任何一个该 Topic 的 partition 作为新的 leader,该策略可用性高,但可靠性没有保证。其可能会导致大量消息的丢失。

即ISR没有从OSR找

3.8 消息消费的 重复消费、数据丢失问题分析

生产者发送给Kafka分区的每条消息都有一个偏移量:用于标识每条消息的顺序索引号。要跟踪已处理的消息,您的消费者需要提交已处理消息的偏移量。

除非您手动触发提交,否则您最有可能使用Kafka使用者自动提交机制。自动提交是开箱即用的,默认情况下每五秒提交一次。

卡夫卡的消费者不知道你对这个消息做了什么,而且对于提交补偿更加冷漠。就消费者而言,只要收到消息,就会被“处理”。

所以现在想象一下,你的消费者已经吸收了1000条消息并将它们缓存到内存中。然后自动提交触发,提交这1,000条消息的偏移量。但是,假设您的服务现在使用了太多内存,并且在处理完所有消息之前会被OOM终止信号强行关闭。这样就永远不会处理剩余的可能是数百条消息,这就是数据丢失

相反的情况也是可能的。您可以成功处理这1,000条消息,然后在提交偏移量之前发生问题如硬件故障等。在这种情况下,您将在消费者重新平衡后重新处理另一个实例上的数百条消息,这就是数据重复(即发生Rebalance的情况)。


首先说明一些问题 :

  • 1、如果取消了自动提交,除非手动提交offset,否则任何时候都不会提交。

  • 2、poll kafka的消息时候,客户端程序每次都会带上需要的offset的位置,kafka按这个给客户端消息,客户端程序本身也会“缓存”这个offset位置,所以在客户端不重启、没有发生Rebalance的情况下就算关闭自动提交也是不会拉取到重复消息的

  • 3、不管是自动提交还是手动提交,只有第一次poll是从consumer_offset获取

  • 4、客户端自己可以灵活的控制自己需要的offset位置,而不是服务器控制。

  • 5、查阅官网,发现一个属性max.poll.interval.ms,官网描述如下:
    在这里插入图片描述
    基本意思就是消费者两次调用poll()取数据的最大延迟时间,超过这个时间消费组会发生rebalance。

    消费者第一次poll到数据后,会开始消费,直到本次数据处理完毕,才会进行下一次poll,也就是说:

    max.poll.records * (处理能力) <= max.poll.interval.ms,程序即可正常消费。

    从上面公式可以看到,我们只要保证程序处理能力稳定,不会随着时间或者数据量增大,那这rebalacnce就不会出现了。

    可以采用异步消费的方式。


总结:

(1) 当 Consumer 由于消费能力较低而引发了消费超时时,则可能会形成重复消费。

解决方案:

  • 延长max.poll.interval.ms时间
  • 减少max.poll.records数量,即poll一次的最大消息数量,或者异步消费
  • 开启自动提交

(2) 当 Consumer 消费了消息但还未提交 offset 时宕机(Rebalance的情况),则这些已被消费过的消息会被重复消费。

Kafka一般日志系统用的比较多、大数据用的也比较多,原因是数据丢失一部分,或者多了重复的数据,影响不大

猜你喜欢

转载自blog.csdn.net/weixin_41947378/article/details/108619757