Kafka

3、Kafka简介

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

Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。

Kafka 本质上是一个 MQ(Message Queue),使用消息队列的好处?(面试会问)

  • 解耦:允许我们独立的扩展或修改队列两边的处理过程。
  • 可恢复性:即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
  • 缓冲:有助于解决生产消息和消费消息的处理速度不一致的情况。
  • 灵活性&峰值处理能力:不会因为突发的超负荷的请求而完全崩溃,消息队列能够使关键组件顶住突发的访问压力。
  • 异步通信:消息队列允许用户把消息放入队列但不立即处理它。

3.2. Kafka的优点

  • 解耦

    在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息系统在处理过程中间插入了一个 隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

  • 冗余

    ​ 有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久 化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删 除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从 而确保你的数据被安全的保存直到你使用完毕。

  • 扩展性

    ​ 因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过 程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。

  • 灵活性&峰值处理能力

    ​ 在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理 这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的 访问压力,而不会因为突发的超负荷的请求而完全崩溃。

  • 可恢复性

    ​ 系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理 消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。 顺序保证 在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按 照特定的顺序来处理。Kafka保证一个Partition内的消息的有序性。

  • 缓冲

    ​ 在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少 的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行——写入队列的处理会尽可能的快速。该 缓冲有助于控制和优化数据流经过系统的速度。

  • 异步通信

    ​ 很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入 队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

4、Kafka系统架构

在这里插入图片描述

在这里插入图片描述

4.1. Broker Kafka

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

4.2. Topic 类别/主题

  • 每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic

  • 类似于数据库的table或者ES的Index

  • 物理上不同Topic的消息分开存储 。

  • 逻辑上一个Topic的消息虽然保存于一个或多个broker上,但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处 。

  • 创建流程

    • 1.controller在ZooKeeper的/brokers/topics节点上注册watcher,当topic被创建,则controller会通过watch得到该topic的partition/replica分配。
      2.controller从/brokers/ids读取当前所有可用的broker列表,对于set_p中的每一个partition:
      	2.1从分配给该partition的所有replica(称为AR)中任选一个可用的broker作为新的leader,并将AR设置为新的ISR
      	2.2将新的leader和ISR写入/brokers/topics/[topic]/partitions/[partition]/state
      3.controller通过RPC向相关的broker发送LeaderAndISRRequest。
      
  • 删除流程

    • 1.controller在zooKeeper的/brokers/topics节点上注册watcher,当topic被删除,则controller会通过watch得到该topic的partition/replica分配。
      2.若delete.topic.enable=false,结束;否则controller注册在/admin/delete_topics上的watch被fire,controller通过回调向对应的broker发送StopReplicaRequest。
      

4.3. Partition 分片/分区

在这里插入图片描述

  • topic中的数据分割为一个或多个partition

  • 每个topic至少有一个partition,当生产者产生数据的时候,根据分配策略,选择分区,然后将消息追加到指定的分区的末尾(队列)

    • ## Partation数据路由规则
      1. 指定了 patition,则直接使用;
      2. 未指定 patition 但指定 key,通过对 key 的 value 进行hash 选出一个 patition
      3. patition 和 key 都未指定,使用轮询选出一个 patition。
      
  • 每条消息都会有一个自增的编号:标识顺序, 用于标识消息的偏移量。

  • 每个partition中的数据使用多个segment文件存储

  • partition中的数据是有序的(外部无序),不同partition间的数据丢失了数据的顺序。

  • 如果topic有多个partition,消费数据时就不能保证数据的顺序。严格保证消息的消费顺序的场景下,需要将partition数目设为1。

4.4. replication 备份

  • 数据会存放到topic的partation中,但是有可能分区会损坏
  • 我们需要对分区的数据进行备份(备份多少取决于你对数据的重视程度)
  • 我们将分区的分为Leader(1)和Follower(N)
    • Leader负责写入和读取数据
    • Follower只负责备份
    • 保证了数据的一致性
  • 备份数设置为N,表示主+备=N(参考HDFS)

4.5. Leader 领导者

  • 每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的 partition

  • 1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的leader
    2. producer 将消息发送给该 leader
    3. leader 将消息写入本地 log
    4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK
    5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后commit 的 offset) 并向 producer 发送 ACK
    

4.6. Follower 跟随者

  • Follower跟随Leader, 只做备份用;所有写请求都通过Leader路由,数据变更会广播给所有Follower, Follower与Leader保持数据同步
  • 如果Leader失效,则从Follower中选举出一个新的Leader
  • 当Follower挂掉、卡住或者同步太慢,leader会把这个follower从“**in sync replicas”(ISR)**列表中删除,重新创建一个Follower。

4.7. producer 生产者

  • 生产者数据的发布者,该角色将消息发布到Kafka的topic中
  • 生产者发送的消息,存储到一个partition中,生产者也可以指定数据存储的partition。
  • broker接收到生产者发送的消息后,broker将该消息追加到当前用于追加数据的segment文件中

4.8. Consumer Group 消费组

  • 每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不 指定group name则属于默认的group)。
  • 将多个消费者集中到一起去处理某一个Topic的数据,可以更快的提高数据的消费能力
  • 整个消费者组共享一组偏移量(防止数据被重复读取),因为一个Topic有多个分区

在这里插入图片描述

4.9. consumer 消费者

  • 消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。

  • kafka 提供了两套 consumer API:

    • 1. The high-level Consumer API
      2. The SimpleConsumer API
      
  • high-level consumer API 提供了一个从 kafka 消费数据的高层抽象,而 SimpleConsumer API 则 需要开发人员更多地关注细节。

4.10. offset 偏移量

  • 可以唯一的标识一条消息
  • 偏移量决定读取数据的位置,不会有线程安全的问题,消费者通过偏移量来决定下次读取的消息
  • 消息被消费之后,并不被马上删除,这样多个业务就可以重复使用kafka的消息
  • 我们某一个业务也可以通过修改偏移量达到重新读取消息的目的,偏移量由用户控制
  • 消息最终还是会被删除的,默认生命周期为1周(7*24小时)

4.11. Zookeeper

  • kafka 通过 zookeeper 来存储集群的 meta 信息
  • 帮助选举

在这里插入图片描述

在这里插入图片描述

5、Kafka0.11.0.3环境搭建

  • 基于Zookeeper搭建

搭建Zookeeper集群.https://blog.csdn.net/weixin_43660536/article/details/118369963
Kafka 0.11.0.3 集群搭建.https://blog.csdn.net/weixin_43660536/article/details/119189414

6、Kafka数据存储

在这里插入图片描述

  • topic在物理层面以partition为分组,一个topic可以分成若干个partition
  • partition还可以细分为Segment,一个partition物理上由多个Segment组成
  • Segment 文件由两部分组成,分别为“.index”文件和“.log”文件,分别表示为 Segment 索引文件和数据文件.index文件中的元数据指向对应.log文件中 Message 的物理偏移量
    • log.segment.bytes:单个segment可容纳的最大数据量,默认为1GB
    • log.segment.ms:Kafka在commit一个未写满的segment前,所等待的时间(默认为7 天)
    • partition全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值
    • 数值大小为64位,20位数字字符长度,没有数字用0填充。
    • .index文件消息都具有固定的物理结构,包括:offset(8 Bytes)、消息体的大小(4 Bytes)、crc32(4 Bytes)、 magic(1 Byte)、attributes(1 Byte)、key length(4 Bytes)、key(K Bytes)、payload(N Bytes)等等字段,可以确定一条消息的大小,即读取到哪里截止。
    • index索引 顺序存储与读写(默认10M),内部自编号
第一个segment
00000000000000000000.index
00000000000000000000.log
第二个segment,文件命名以第一个segment的最后一条消息的offset组成
00000000000000170410.index
00000000000000170410.log
第三个segment,文件命名以上一个segment的最后一条消息的offset组成
00000000000000239430.index
00000000000000239430.log

7、生产者数据安全

7.1. 数据分区

  • 分区原因
    1. 方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,
    2. 一个 Topic 又可以有多个 Partition 组成,因此可以以 Partition 为单位读写了。
    3. 可以提高并发,因此可以以 Partition 为单位读写了。
  • 分区原则
    • 将 Producer 发送的数据封装成一个 ProducerRecord 对象。对象包含:
      • topic:string 类型,NotNull。
      • partition:int 类型,可选。
      • timestamp:long 类型,可选。
      • key:string 类型,可选。
      • value:string 类型,可选。
      • headers:array 类型,Nullable。

7.2. 数据可靠性保证

7.2.1. ACK机制
  • 为保证 Producer 发送的数据,能可靠地发送到指定的 Topic
  • Topic 的每个 Partition 收到 Producer 发送的数据后,都需要向 Producer 发送 ACK(ACKnowledge 确认收到)。
  • 如果 Producer 收到 ACK,就会进行下一轮的发送,否则重新发送数据。
7.2.2. ACK时机
  • 部分 Follower 与 Leader 同步完成,Leader 发送 ACK
  • 全部 Follower 与 Leader 同步完成,Leader 发送 ACK。
  • ISR(部分)
    • AR : Assigned Replicas 用来标识副本的全集
    • OSR :out -sync Replicas 离开同步队列的副本
    • ISR :in -sync Replicas 加入同步队列的副本
    • ISR = Leader + 没有落后太多的副本;
    • AR = OSR+ ISR
  • Leader维护了一个动态的 in-sync replica set(ISR 和 Leader 保持同步的 Follower 集合)
  • 当 ISR 集合中的 Follower 完成数据的同步之后,Leader 就会给 Follower 发送 ACK。
  • 如果 Follower 长时间未向 Leader 同步数据,则该 Follower 将被踢出 ISR 集合,判断标准:
    • 超过10秒钟没有同步数据 replica.lag.time.max.ms=10000 主
    • 副节点差4000条数据 rerplica.lag.max.messages=4000
  • Leader 发生故障后,就会从 ISR 中选举出新的 Leader
    • kafka采用一种降级措施来处理:
    • 选举第一个恢复的node作为leader提供服务,以新的数据为基准,这个措施被称为脏leader选举
7.2.3. ACK应答机制
  • Kafka 为用户提供了三种可靠性级别,用户根据可靠性和延迟的要求进行权衡
  • Producers可以选择是否为数据的写入接收ack,有以下几种ack的选项:request.required.acks
  • acks=0:
    • 这意味着 Producer 无需等待来自 Broker 的确认而继续发送下一批消息。
    • 当 Broker 故障时有可能丢失数据。
  • acks=1
    • Producer 在 ISR 中的 Leader 已成功收到的数据并得到确认后发送下一条 Message。
    • 如果在 Follower 同步成功之前 Leader 故障,那么将会丢失数据。
  • acks=-1
    • Producer 需要等待 ISR 中的所有 Follower 都确认接收到数据后才算一次发送完成,可 靠性最高。
    • 在 Broker 发送 ACK 时,Leader 发生故障,则会造成数据重复。
7.2.4. 故障处理

在这里插入图片描述

  • LEO:每个副本最大的 Offset
  • HW:消费者能见到的最大的 Offset,ISR 队列中最小的 LEO
  • Follower 故障
    • Follower 发生故障后会被临时踢出 ISR 集合,待该 Follower 恢复后,Follower 会 读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 Leader 进行同步数据操作。
    • 等该 Follower 的 LEO 大于等于该 Partition 的 HW,即 Follower 追上 Leader 后,就可以重新加入 ISR 了。
  • Leader 故障
    • Leader 发生故障后,会从 ISR 中选出一个新的Leader,之后,为保证多个副本之间的数据一致性,其余的 Follower会先将各自的log文件高于HW的部分截掉,然后从新的 Leader 同 步数据
    • 注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
7.2.5. 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。

7.3. 数据存储机制

  • 无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据:

  • 1. 基于时间:log.retention.hours=168
    2. 基于大小:log.retention.bytes=1073741824
    

8、消费者数据安全

8.1. 消费方式

  • Consumer 采用 Pull(拉取)模式从 Broker 中读取数据。
    • Consumer 采用 Push(推送)模式,Broker 给 Consumer 推送消息的速率是由 Broker 决 定的,很难适应消费速率不同的消费者。
  • 而 Pull 模式则可以根据 Consumer 的消费能力以适当的速率消费消息
  • 消费者从 Broker 主动拉取数据,需要维护一个长轮询
  • 如果 Kafka 没有数据,消费者可能会陷入循环中,一直返回空数据
  • 消费者在 消费数据时会传入一个时长参数 timeout。如果没有数据,Consumer会等待 timeout时间之后再返回

8.2. 分区分配策略

Kafka 有三种分配策略:

  • RangeAssignor分配策略(默认)
  • RoundRobinAssignor策略,当消费者组内消费者发生变化时,会触发分区分配策略(方法重新分配)。
  • StickyAssignor分配策略:① 分区的分配要尽可能的均匀;② 分区的分配尽可能的与上次分配的保持相同。
8.2.1. RoundRobin策略
  • RoundRobin 轮询方式将分区所有作为一个整体进行 Hash 排序,消费者组内分配分区个数最大差别为 1,是按照组来分的,可以解决多个消费者消费数据不均衡的问题。
  • 当消费者组内订阅不同主题时,可能造成消费混乱

在这里插入图片描述

8.2.2. Range模式
  • Range 方式是按照主题来分的,不会产生轮询方式的消费混乱问题。

在这里插入图片描述

8.2.3. StickyAssignor分配策略

​ 从字面意义上看,Sticky是“粘性的”,可以理解为分配结果是带“粘性的”——每一次分配变更相对上一次分配做最少的变动(上一次的结果是有粘性的),其目标有两点:

  1. 分区的分配尽量的均衡

  2. 每一次重分配的结果尽量与上一次分配结果保持一致

     当这两个目标发生冲突时,优先保证第一个目标。第一个目标是每个分配算法都尽量尝试去完成的,而第二个目标才真正体现出StickyAssignor特性的。
    
  • StickyAssignor是比RangeAssignor和RoundRobinAssignor更好的分配方式,不过它的实现也更加的复杂

在这里插入图片描述

在这里插入图片描述

8.3. Offset 的维护

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

9、Kafka的事务性

幂等和事务是Kafka 0.11.0.0版本引入的两个特性,以此来实现EOS(exactly once semantics,精确一次处理语义)

9.1. Kafka幂等性

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数

  • 没有幂等性的情况下就会重复发送数据。

  • Kafka的幂等性机制能保证单个分区不会重复写入数据,而实现幂等性的核心就是引入了producer id 和 sequence number这两个概念

  • 判断流程

    1. 每个producer都会被分配一个PID,这个PID对用户而言是完全透明的。
    2. 对于每个PID,消息发送到的每一个分区都有对应的序列号Seq Num,这些序列号从0开始单调递增
    3. 生产者每发送一条消息就会将对应的序列号的值加1。
    4. broker端会在内存中为每一对维护一个序列号。
      1. 如果SN_new = SN_old + 1时,broker才会接收它
      2. 如果SN_new< SN_old + 1,那么说明消息被重复写入,broker可以直接将其丢弃。
      3. 如果SN_new> SN_old + 1,那么说明中间有数据尚未写入,出现了乱序,暗示可能有消息丢失,这个异常是一个严重的异常。

9.2. kafka 事务

Kafka事务性主要是为了解决幂等性无法跨Partition运作的问题,事务性提供了多个Partition写入的原子性。

即写入多个Partition要么全部成功,要么全部失败,不会出现部分成功部分失败这种情况。

为了实现这种机制,我们需要应用能提供一个唯一id:TransactionnalId(也叫 txn.id,后面会详细讲述),即使故障恢复后也不会改变,txn.id 可以跟内部的 PID 1:1 分配,它们不同的是 txn.id 是用户提供的,而 PID 是 Producer 内部自动生成的(并且故障恢复后这个 PID 会变化),有了 txn.id 这个机制,就可以实现多 partition、跨会话的 EOS 语义。

当用户使用 Kafka 的事务性时,Kafka 可以做到的保证:

1. **跨会话的幂等性写入**:即使中间故障,恢复后依然可以保持幂等性; 
2. **跨会话的事务恢复**:如果一个应用实例挂了,启动的下一个实例依然可以保证上一个事务完成(commit 或者 abort); 
3. **跨多个 Topic-Partition 的幂等性写入**,Kafka 可以保证跨多个 Topic-Partition 的数据要么全部写入成功,要么全部失败,不会出现中间状态。

Consumer 端很难保证一个已经 commit 的事务的所有 msg 都会被消费。

  1. 对于 compacted – topic,在一个事务中写入的数据可能会被新的值覆盖
  2. 一个事务内的数据,可能会跨多个 log segment,如果旧的 segmeng 数据由于过期而被清除,那么这个事务的一部分数据就无法被消费到了;
  3. Consumer 在消费时可以通过 seek 机制,随机从一个位置开始消费,这也会导致一个事务内的部分数据无法消费;
  4. Consumer 可能没有订阅这个事务涉及的全部 Partition

10、Kafka优化

10.1. Partition 数目

一般来说,每个partition 能处理的吞吐为几MB/s,增加更多的partitions意味着:

  • 更高的并行度与吞吐
  • 可以扩展更多的(同一个consumer group中的)consumers
  • 若是集群中有较多的brokers,则可更大程度上利用闲置的brokers
  • 但是会造成Zookeeper的更多选举
  • 也会在Kafka中打开更多的文件

调整准则

  1. 一般来说,若是集群较小(小于6个brokers),则配置2 x broker数的partition数。在这里主 要考虑的是之后的扩展。若是集群扩展了一倍(例如12个),则不用担心会有partition不足 的现象发生
  2. 一般来说,若是集群较大(大于12个),则配置1 x broker 数的partition数。因为这里不需 要再考虑集群的扩展情况,与broker数相同的partition数已经足够应付常规场景。若有必 要,则再手动调整
  3. 考虑最高峰吞吐需要的并行consumer数,调整partition的数目。若是应用场景需要有20个 (同一个consumer group中的)consumer并行消费,则据此设置为20个partition
  4. 考虑producer所需的吞吐,调整partition数目(如果producer的吞吐非常高,或是在接下来两年内都比较高,则增加partition的数目)

11.2. Replication factor

  • 此参数决定的是records复制的数目,建议至少 设置为2,一般是3,最高设置为4
  • 更高的replication factor(假设数目为N)意味着:
    • 系统更稳定(允许N-1个broker宕机)
    • 更多的副本(如果acks=all,则会造成较高的延时)
    • 系统磁盘的使用率会更高(一般若是RF为3,则相对于RF为2时,会占据更多50% 的磁盘空 间)

11.3. 批量写入

  • 为了大幅度提高producer写入吞吐量,需要定期批量写文件

  • 每当producer写入10000条消息时,刷数据到磁盘
    log.flush.interval.messages=10000
    每间隔1秒钟时间,刷数据到磁盘
    log.flush.interval.ms=1000
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值