关于java:java开发之开源平台Kafka知识总结分享

31次阅读

共计 3788 个字符,预计需要花费 10 分钟才能阅读完成。

kafka 的根本体系结构
一个残缺的 kafka 消息中间件应该蕴含如下几个节点:

  1. 生产者:生产音讯的节点
  2. 消费者:生产音讯的节点
  3. broker:接管生产者发送音讯存储的节点
  4. zookeeper:治理保护 broker 集群,保留 broker 集群的元数据信息,保障集群高可用。


kafka 音讯存储形式
kafka 是如何进行音讯存储的?如何保障整个集群的负载平衡和高可用?解说之前须要对 kafka 的一些基本概念做下补充
主题:生产者发送一个音讯都必须挂靠一个主题,也就是说咱们发的音讯都是发往这个主题下
分区:实质上就是存储音讯的一个物理文件概念,分区内的每一条音讯都是有序的,遵循 FIFO 准则
音讯:发送的一条条音讯就是寄存在分区之上的
正本:kafka 往往都会搭建成集群,所以雷同音讯是有多份的,java 培训也就是分区在集群上存在多份。而集群中,分区都会分为 leader 正本和 follower 正本,leader 正本次要负责读 / 写申请,而 follower 正本次要负责同步 leader 正本数,保障 leader 正本节点宕机时,依然可能通过选举机制保障集群高可用
broker:kafka 集群中每一个节点
生产者:生成音讯的节点
消费者:生产音讯的节点,同一条消只能被生产组内的一个消费者生产
生产组:kafka 中每个消费者都会属于一个消费者组
ok,通过下图再来直观感触下以上几个基本概念

音讯存入 kafka 集群中须要有几个步骤

  1. 创立主题指定分区数量和正本数,同时会依据调配算法将分区正本调配到指定 broker
  2. 生产者向该主题发送音讯
  3. kafka 依据音讯的 key 确定对应的分区(如果没有 key 主动生一个),将音讯发往该分区的 leader 正本节点

2、3 步没什么可说的,着重看下 kafka 是如何将分区正本调配给集群 broker 的,来做到负载平衡。
现假如主题 A 有 x 个分区,3 个正本数。正本调配规定会依据设定的正本数量对主题下的每个分区进行逐个调配,首先对分区 0 的正本数量调配完后,紧接着才调配分区 1 的正本数量。而不是把主题的所有分区进行第一个正本数的调配,再接着第二个正本数的调配。说得有点绕,能够看下图了解了解:

那么具体调配规定的大抵算法是这样子的:

  1. 随机确定分区 0 第一个正本的 broker 地位,此时该分区 0 调配到的 broker 即为咱们 leader 正本存储的节点。(再强调一遍,对于读 / 写分区 0 的音讯都在这个节点进行)
  2. 随机确定分区 0 下一副本调配到 broker 的偏移步长,而后对残余正本数基于这个偏移步长定位 broker

具体计算公式如下
分区 0 第一个正本 (leader 正本) 的 broker 地位:
(分区 0 的索引地位 + 随机起始索引)% broker 数
分区 0 残余正本 broker 地位:
val shift = 1+(随机的偏移步长 + 第 i 个正本的索引 i)%(broker 数 -1)
最终地位 = (第一个正本调配的 broker 地位 + shift) % broker 数
随机的偏移步长:调配下一个分区的时候,会在上一个分区偏移步长之上加 1

通过随机起始索引和随机的偏移步长,可能尽量的保障所有分区的 leader 正本平均的调配到 kafka 集群。而 leader 正本的节点负责所有的读写操作,这样就保障不会因为 leader 正本散布过于集中而导致负载不平衡问题。
生产者端外围解决流程
生产者在创立音讯的时候,必须在 broker 上创立一个主题并指定分区数和分区正本数量,尔后音讯发送时会往该主题下的分区进行发送。主题创立结束后,进行音讯发送,能够分为如下几个外围步骤

  1. 实例化外围组件

此阶段会实例化一些外围数据 如 broker 集群的外围元数据信息、可用的分区列表、音讯 key 和 value 的序列化形式。

  1. 发送音讯

首先会将音讯填入缓冲区而后另开线程从缓冲区中批量取出数据发送到 broker,缓冲区的数据大体设计构造如下。

填入缓冲区的规定会依据音讯的 key 计算出音讯须要放入那个分区,分区外部的音讯是有序的,同时是一种先进先出的双端队列构造(FIFO)。之所以是双端队列构造是因为它外部有一个重试机制,在音讯发送失败时,保障下次取的音讯还是那个未发送的。而在音讯写入缓冲区的时候,只须要加在队列的尾部即可。整个发送音讯的大体外围流程如下:

消费者端外围解决流程
生产端进行音讯生产的次要外围流程分为以下几个步骤:

  1. 生产组内的消费者依据调配策略,订阅分区
  2. 从指定分区中拉取音讯,进行生产
  3. 提交生产偏移量

• 生产组内的消费者依据调配策略订阅分区

kafka 中提供了 3 种调配策略:RoundRobinAssignor、RangeAssignor、StickyAssignor
RoundRobinAssignor:round-robin 是一种轮询的策略形式,它将订阅主题的分区和消费者进行排序,而后将所有主题的分区平均调配给生产组内的每个消费者(PS: 相似与咱们斗地主发牌的形式,分区就是牌,消费者就是玩游戏的人)。
假如有两个主题 t0、t1 别离有 3 个分区(PS:总共有 6 个分区 t0p0,t0p1,t0p2,,t1p0,t1p1,t1p2),同一个生产组内有两个消费者(c0,c1)进行订阅,那么分区的调配最终后果如下:
c0:[t0p0,t0p2,t1p1]
c1:[t0p1,t1p0,t1p2]


RangeAssignor: range 的调配策略(默认的调配策略),首先对消费者依照字典程序进行排序,而后对一个主题下的所有分区平均调配,调配残余的分区就会依照消费者程序逐个调配给每个消费者,调配完后接着调配下一个主题的分区,逻辑同第一个一样。
假如有两个主题 t0、t1 别离有 3 个分区(PS:总共有 6 个分区 t0p0,t0p1,t0p2,t1p0,t1p1,t1p2),那么分区调配的最终后果如下:
c0:[t0p0,t0p2,t1p0,t1p2]
c1:[t0p1,t1p1]

StickyAssignor: 是对于 round-robin 和 range 更近一步的优化。因为这两种策略当存在同一个生产组内消费者订阅的主题不一样时,那么么可能会存在某个消费者调配的分区较多的状况,导致不平衡问题。而 sticky 策略对于这种状况也能进行更优的调配,同时对于生产组内新上线 / 下线消费者时,会基于之前已调配的分区上进行调配,而不是从新进行调配,它尽可能的保障少挪动分区(PS:round-robin 和 range 策略对于新上线、下线消费者时,会从新进行分区调配)
举个例子有 3 个同属于一个生产组的 Consumer:C0、C1、C2,都订阅了 4 个 Topic:T0、T1、T2、T3,每个 Topic 有 2 个分区
那么 StickyAssignor 的调配后果如下图所示(减少 RoundRobinAssignor 调配作为比照):

• 从指定分区中拉取音讯,进行生产

fetcher.fetchedRecords 判断是否有数据,无数据调用 fetcher.sendFetches()拉取数据 fetcher.sendFetches() 会依据元数据信息,确定消费者须要往哪几个分区拉取音讯,同时创立 FetchRequest 的申请音讯(此阶段会确定区音讯偏移量的起始地位),而后调用 ConsumerNetworkClient.send 办法获取音讯。
这边须要着重讲一下消费者如何确定生产偏移量的起始地位,起始地位的确定跟 auto.offset.reset 配置值有比拟大的关系,次要有两个外围值 earliest 和 latest(默认策略)。消费者会先查看本地是否曾经有提交的偏移量,如有那么依据以后偏移量持续往下读取。如果没有那么会依据 auto.offset.reset 的值确定偏移量。earliest 和 latest 都会向 kafka 集群中获取已提交的偏移地位,基于该偏移量持续生产。如果没有已提交的偏移量,earliest 会从头生产,latest 将生产新产生的音讯(PS:latest 这种策略如果新建生产组的话在公布利用阶段呈现音讯失落的状况)
不太明确的话举个例子, 假如 6 条音讯,生产组 A 还有两条音讯未生产。
当 reset 为 earliest: 重启生产组 A, 收到 2 条音讯; 新建生产组 B, 收到 6 条音讯.
当 reset 为 latest: 重启生产组 A, 收到 2 条音讯; 新建生产组 B,无收到音讯.
• 提交生产偏移量

手动提交:客户端调用相应 API 进行提交
主动提交:主动提交并不是通过定时工作去周期性的提交,而是在一些特定事件产生时触发进行提交
两种提交形式都是最终调用 ConsumerCoorditor 的同步提交和异步提交办法。能够通过设置 enable.auto.commit 属性来指定手动还是主动提交。
保障分布式事务
对于发送端,kafka 外部有本人的重试次数配置,当重试次数达到,音讯还未发送胜利,咱们能够采取日志记录,后续通过弥补工作进行重试。
对于生产端,kafka 是通过音讯偏移量来拉取音讯,所以对于 broker 发送给到生产端失败这个问题就不存在了。咱们探讨的只有在生产端接管到数据,而后生产失败的这种状况。生产失败如果咱们将偏移量重置,下次不就能够持续拉取了吗?但此计划会存在肯定的问题,kafka 音讯在分区内都是程序读和程序写的,如果前一条音讯始终生产失败,那么会导致后续音讯生产不了,产生沉积问题。因而咱们仍然还是通过记录日志的形式,将生产失败的音讯记录,后续通过定时工作进行弥补,来保证数据的最终统一。

正文完
 0