咱们来自字节跳动飞书商业运用研发部(Lark Business Applications),现在咱们在北京、深圳、上海、武汉、杭州、成都、广州、三亚都设立了办公区域。咱们注重的产品范畴首要在企业经历办理软件上,包含飞书 OKR、飞书绩效、飞书招聘、飞书人事等 HCM 范畴体系,也包含飞书批阅、OA、法务、财政、采购、差旅与报销等体系。欢迎各位参加咱们。

本文作者:飞书商业运用研发部 张博

欢迎咱们注重飞书技能,每周定期更新飞书技能团队技能干货内容,想看什么内容,欢迎咱们谈论区留言~

摘要

Kafka 是一款十分优异的开源音讯引擎,以音讯吞吐量高、可动态扩容、可耐久化存储、高可用的特性,以及完善的文档和社区支撑成为现在最盛行的音讯行列中间件。

Kafka 的开发社区一向十分活跃,在音讯引擎的范畴取的不俗成果之后,不断拓宽自己的范畴,在依据事情的流处理平台方向一向发力,不断自我更新迭代力图成为这个范畴内的现实标准。

Kafka 的音讯引擎功用十分强大,可是一向没有停下自我打破的脚步,随着 3.0 版别的中 KRaft 协议的推出,Zookeeper 的退出进程正式发动,Kafka 开端了又一次的自我蜕变。

ZK 的移除是一个十分大胆的举动,由于 ZK 在 Kafka 的集群办理中居于中心的方位,不会容易替代,那为什么 Kafka 挑选了自行完结推举机制的道路?

此外,虽然 Kafka 具备许多优异的特性,这些现在被视为最佳实践的特性也是不断演化而来的,从其不断晋级改善的进程中也能直接反映出出产环境所面对的现实问题,那么 Kafka 在实践的出产环境中的体现终究怎样?

作为事务方,运用 Kafka 作为音讯中间件进行事务开发,确保服务平稳运转需求避开哪些雷区?

这篇文档将从一个比较高的视角,从 Kafka 的规划理念、架构到完结层面进行深化解读,随着对 Kafka 相关机制的深化了解,这些问题的答案将浮出水面。

须知事项

  • 这篇文档依据 Kafka 最近刚刚发布的 3.2 版别源码为根底进行介绍,首要评论 Java 和 Scala 言语完结的原版客户端和服务端,其他言语版别的客户端与这篇文档介绍的机制在完结上会有较大收支,需求留意
  • 此外,字节的事务许多运用的都是自研的 BMQ [3],在客户端协议上是彻底兼容的,可是服务端进行了彻底的重构,本文介绍的相关服务端机制并不适用
  • Kafka 整个项目包含 Core、Connect、Streams,只要 Core 这一部分是咱们一般说的中心音讯引擎组件,别的两个都是依据这个中心完结的上层运用,这篇文章首要介绍的便是 Kafka Core 相关的内容,下面的 「Kafka 的运用架构部分」会对这一点做扼要介绍

名词对照

下面的表格给出了 Kafka 中呈现的一些高频和重要概念的对照解说

英文名 中文名 解说 补白
KIP Kafka 改善提案 KIP(Kafka Improvement Proposal)是针对 Kafka 的一些严重功用变更的提案,一般包含改善动机、提议的改善内容、接口变更等内容
Partition 分区 一个独立不行再切割的音讯行列,分区中会有多个副本保存音讯,他们的状况应该是一致的 Kafka 分区副本的同步机制不是纯异步的,有高水位机制去盯梢从副本的同步进展,并且有对应的领导者副本推举机制确保分区全体对外可见的音讯都是已提交的
Replica 副本 分区中音讯的物理存储单元,一般对应磁盘上的一个日志目录,目录中会对音讯文件进一步进行分段保存
Leader Replica 主副本、领导者副本 指一个 Partition 的多个副本中,对外供给读写服务的那个副本 Kafka 集群规划有对等方位的组件是 Controller
Consumer 顾客 Kafka 客户端消费侧的一个人物,担任将 Broker 中的音讯拉取到客户端本地进行处理,还能够运用 Kafka 供给的顾客组办理机制进行消费进展的盯梢
Consumer Group Leader 顾客组领导者 一般指 Consumer Group 中担任生成分区别配计划的 Consumer 这个概念十分容易和上面的 Leader Replica 混杂
Log start offset 音讯开端偏移 Log start offset,Kafka 分区音讯可见性的起点 此方位对应一条音讯,对外可见能够消费
LSO 上次安稳偏移 Last stable offset,和 Kafka 事务相关的一个偏移 当消费端的参数isolation.level 设置为“read_committed”的时分,那么顾客就会疏忽事务未提交的音讯,既只能消费到LSO(LastStableOffset)的方位
LEO 音讯中止偏移 Log end offset,Kafka 分区音讯的结尾 LEO 是下一条音讯将要写入的方位,对外不行见不行供消费
HW 高水位 High water mark,用于操控音讯可见性,HW 以下的音讯对外可见 HW 的方位或许对应一条音讯,可是对外不行见不行以消费,HW 的最大值是 LEO
LW 低水位 Low water mark,用于操控音讯可见性,LW 及以上的音讯对外可见 一般状况下和 Log start offset 能够等价替换,代码里也是这个逻辑
ISR 已同步副本 In sync replica 指满意副本同步要求的副本调集,包含领导者副本 副本同步是依照时刻差进行断定的,而非音讯偏移的推迟

Kafka 的运用生态

下面这张是我依据 Confluent 博客的一张材料图重绘的 Kafka 运用生态架构图,在正式开端介绍本文的主题之前,咱们先了解一下 Kafka 的整个运用生态

这张图中居于中心方位的是 Kafka Core 的集群,也是咱们常用的音讯引擎的这部分功用,是咱们这篇文档重点介绍的目标

在中心的周围,第一层是 Producer 和 Consumer 的根底 API,供给根底事情流音讯的推送和消费

而依据这些根底 API Kafka 供给了愈加高档的 Connect API,能够完结 Kafka 和其他数据体系的衔接,比方音讯数据主动推送到 MySQL 数据库或许将 RPC 恳求转换为事情流音讯进行推送

此外,Kafka 依据自己的音讯引擎打造了一个流式核算平台 Streams,供给流式的核算和存储一体化的服务

Kafka Core 架构

Kafka Core 架构部分的解读从模型、人物和实体、典型架构三个方向层层递进进行介绍

音讯模型

Kafka 的音讯模型首要由出产消费模型、人物和实体,以及实体联系构成,前者表明了音讯的出产消费办法,后者描绘了为了完结前者,其内部人物和实体存在怎样的逻辑联系

根本音讯出产消费模型如下图所示:

流程图 (3).jpg

图中展现了一个十分根本的出产消费场景,出产端向行列尾部发送音讯,消费端从行列头部开端消费

从左往右看分别是消费端、音讯行列、出产端,这三块咱们分隔进行具体介绍

消费端

在消费端有许多顾客,它们之间用顾客组相关起来

留意图中 Consumer 0 是没有分配到分区进行消费的,由于顾客组首要起个负载均衡的作用,一个分区被两个顾客消费从事务视角来看便是在重复消费了

对现已分配到分区的顾客来说,消费从行列的头部开端,在 HW 前完毕

音讯行列

音讯行列处于整个音讯模型中心的方位,是衔接出产端和消费端的纽带,Kafka 在功用优化上做的作业最多的便是这一个部分

由于 Kafka 的音讯存储是行列的数据结构,只答应音讯追加写入,这样的规划能最大化利用现有耐久化存储介质的写入功用(SSD 和 HDD 都存在次序写入功用远大于随机写入的特性),完结音讯行列的高吞吐量

此外,Kafka 的行列还规划了高水位机制,防止未被从副本完结同步的音讯被顾客感知并消费

出产端

出产端的 Producer 继续发送音讯到行列中,音讯追加到行列尾部,经过指定分区算法能够决定音讯发往 Topic 下的哪个分区

小结

Kafka 的整个音讯模型仍是依据经典的音讯模型去规划和改善的,音讯模型的规划仍是十分简洁易懂的,它的创新和优势便是在于将这一套模型用分布式的多机办法完结出来,能支撑住大并发、高吞吐量场景下的低时延、高可用的事务需求

当然这套模型之下,还有一些比较小的论题值得去评论,我这儿选了两个论题打开叙说来完毕这一节

Push vs Pull

在 Kafka 界说的音讯模型中,消费端是经过主动拉取音讯的办法来消费的,可是与之对应的还有音讯推送模型,Broker 对出产者推送过来的音讯进行主动分发和推送到消费端

直觉上咱们会觉得这种办法很自然,或许认为这是音讯引擎的仅有范式,可是实践上关于为什么挑选 Pull 的办法来进行消费,Kafka 的官方文档中关于这部分规划有专门列出来,首要评论的点是音讯消费的流控战略应该放在 Broker 端仍是 Consumer 端,感兴趣的能够去阅览一下 Apache Kafka Documentation

零复制(Zero-Copy)

零复制从广义的视点来看不是一种具体的技能完结(仅指操作体系完结的零复制机制),而是一种优化思想或许技巧,针对程序运转中不行变的数据或许不行变的部分尽量削减或许取消内存数据的复制,用内存地址去引证这些数据

Kafka 的音讯行列的中心功用便是进行各种数据的 IO 和转发(IO 密集型运用),零复制带来的收益十分显着:

  • 削减了 JVM 堆内存占用,下降了 GC 导致的服务暂停和 OOM 风险
  • 削减了大批量频频内存复制的时刻,能大幅优化数据吞吐功用

所以很有必要进行这样的优化

Kafka 的实例是运转在 JVM 里的,零复制的技能落地也离不开 Java 运转时供给的环境,具体到完结上首要依靠 Java 供给的 FileChannel 去映射文件

针对音讯拉取消费的场景,直接将日志段 FileChannel 中对应偏移和长度(Kafka 的日志段都有对应的索引文件,所以不需求读取原始音讯日志段文件就能拿到这些信息)的数据发送到网络栈,躲避运用层的数据复制中转

针对音讯推送出产的场景,从网络栈读取出来处理好的音讯直接从内存 Buffer 中向 FileChannel 写入追加,当然这个场景并没有完结严格意义上的零复制(JVM 堆内存存在于用户空间,写入文件中必需求复制到内核),只不过 Kafka 用了 MemoryRecords 这个类依据 Buffer 去办理内存中的音讯,躲避了运用目标结构的办法办理或许存在的内存复制和数据序列化行为(这个优化的思路和 String 以及 StringBuilder 一致)

这儿仅仅以场景的比方供给一些剖析零复制完结机制的视角(体系原生支撑 + 处理逻辑层面优化),零复制独自打开也是一个很大的论题,总体来讲便是在各个环节尽或许削减内存复制的次数,进步数据读写功用

人物和实体

在 Kafka 对上述音讯模型的完结中,界说了一系列担任履行的人物和表达数据结构的实体,每个人物和实体都有其对应的责任鸿沟,这些人物和实体之间一同合作完结整个音讯引擎的运作

Kafka 中有这么一些比较重要的人物和实体:

  • Broker 是一个独立的 Kafka 服务端实例,是最大的实体规划,其他人物的实例都经过目标成员的办法引证进来,自身不担任恳求的处理逻辑
  • Controller 是整个 Kafka 集群的办理者人物,任何集群规划内的状况变更都需求经过 Controller 进行,在整个集群中是个单点的服务,能够经过推举协议进行毛病搬运
  • Replica 是一个独立的音讯行列实体,担任音讯在物理层面上的存储
  • Partition 是逻辑层面的“行列”实体,实践上是一组 Replica 的调集
  • Topic 是 Partition 的实体调集
  • Producer 是音讯出产者人物,会发送音讯到对应主题的分区中,写入到 LEO 的方位去
  • Consumer 是音讯的顾客人物,能消费到 Partition 对外可见的音讯
  • Consumer Group 是 Consumer 的调集实体,并对应一组办理机制用来和谐 Consumer 的消费
  • Group Coordinator 是 Broker 中一个担任办理对应顾客组元数据的人物,比较重要且熟知的功用便是担任消费进展的办理

虽然这儿现已罗列了比较多的人物和实体界说,可是 Kafka 中界说的人物和实体远不止罗列的这些,不过大部分都不是本文需求介绍的相关内容,就不在这儿一一罗列了

上面咱们现已了解了 Kafka 音讯引擎部分的一些规划笼统层面的常识,下面从 Kafka 的完结视点深化介绍一下上面呈现的一些人物和实体

Broker

这一节开端对 Broker 的简介中的界说是一个 Kafka 服务端实例,假如进一步诘问这个实例是什么,在代码中怎样体现的话,答案便是 KafkaServer,这是个承继了 KafkaBroker 的完结类

服务端进程发动的入口就在这儿,此外一些简略的恳求能够直接在 KafkaServer 中处理掉,比方一些读取元数据相关的恳求就不需求进入其他人物的逻辑中处理了,直接读取数据组装结构体回来即可

不过咱们以架构视角去看 Kafka 的话不需求这么具体,就笼统地把它看做服务端实例即可

Controller

Controller 是 Broker 中对 Kafka 集群来说十分重要的一个人物,担任集群规划内的一些要害操作:

  1. 主题的新建和删去
  2. 主题分区的新建、从头分配
  3. Broker 的参加、退出
  4. 触发分区 Leader 推举

每个 Broker 里都有一个 Controller 实例,多个 Broker 的集群一同最多只要一个 Controller 能够对外供给集群办理服务,Controller 能够在 Broker 之间进行毛病搬运

Controller 承当的责任在咱们眼里更像是集群的 Leader,不过在 Kafka 的其他当地也呈现了 Leader 这个人物,防止混杂仍是先记住 Controller 也是集群中的重要人物吧

Partition

流程图 (4).jpg

Partition 是一个独立的音讯行列,从数据结构的视点看能够了解为一个用数组完结的行列,起点是 Log start offset,此偏移会随着音讯过期时刻等装备的影响,逐渐向右移动

HW 是已提交音讯的可见性的鸿沟,仅在此偏移之下的音讯对外是可见的(留意,不含 HW 自身),该偏移的移动和 Kafka 的副本同步机制严密相关,下面会专门介绍此机制

Log start offset 和 HW 一同合作,构成了已提交音讯的可见规划,需求留意的是受 Broker 的音讯过期整理装备的影响,从副本的 Log start offset 的值一般小于等于领导者副本的 Log start offset,可见规划相同会因而缩减

LEO 是音讯行列的结尾,下一条音讯将在这个当地写入,一同 HW 的最大值便是更新到这儿

LW 的作用不是很大,由于分区的 Leader 副本一旦初始化完结,其 Log start offset 的值更新机制便是 LW 的更新机制,两者能够等价替换

上面说的这几个偏移的办理首要和 Kafka 的副本办理机制相关,尤其是 HW 更新机制,由于音讯数据需求在多个副本之间同步,所以需求这样的机制来办理数据同步的进展

Topic

一个 Topic 便是一组 Partition 的调集,作用相当所以给一组 Partition 做了个命名,仅有供给的实践功用应该便是增加调集中的 Partition 数量

值得留意的是,从前版别的 Kafka 中仅运用 Topic 称号作为标识符去区别不同的 Topic,可是新版别中参加了 UUID 去进行判断 KIP-516 ,首要是为了处理删去、新建重名的 Topic 场景下的一些问题

Producer

Producer 是无状况的(不运用事务机制的状况下),和 Partition 之间是多对多的联系

Producer 可依据分区算法自行决定一条音讯应该发往哪个分区,该机制会在下面的文章中进行扼要剖析

Consumer

Consumer 是有状况的(不运用顾客组静态成员或许不运用无顾客组机制的状况下),这个状况以 Consumer Group 为单位进行维护

和 Consumer 自身联系比较大的应该便是音讯消费偏移提交机制了,这个功用在服务端 0.9.0 版别之前的完结是用 ZK 来保存的,可是后边版别中 Kafka 开端用内部主题来耐久化音讯偏移了

Consumer Group

顾客组是 Kafka 中的一个重要实体了,由于顾客组不仅仅是一个顾客的调集,而是以 Group 为中心辐射出一组消费的的办理机制:

  • 分区别配计划,由顾客组推举出的顾客 Leader 履行生成,Coordinator 担任分发
  • 顾客参加、退出机制,由 Coordinator 担任和谐履行
  • 顾客组消费进展办理,由 Coordinator 担任耐久化办理

小结

这一节只从集群大的视角罗列了一些比较重要的人物和实体,在后边的介绍中会有愈加细分的人物和实体的深化介绍

经过对各个人物和实体的概念和责任树立起明晰认知,对咱们了解 Kafka 的集群架构规划、机制原理、问题定位有很大的协助

人物和实体联系

Kafka 中的人物和实体概念比较多,我这儿整理了一下比较中心的这些人物和实体之间的对应联系,能更好地协助了解这些概念

流程图 (5).jpg

留意上面联系图中,Controller 和其他目标之间的联系描绘的是办理视角的,而非目标实体的具体包含联系

由于从目标实体的包含联系上说,Controller 和 Broker 之间是1对1的联系,可是这样的联系描绘没有实践意义

集群架构解析

一个具有代表性的 Kafka 集群一般具备 1 个独立的 ZK 集群、3 个布置在不同节点的 Broker 实例,这儿我以一个这样的典型集群的为例来介绍 Kafka 的全体架构,集群状况如下:

  • 3 Broker、多个 Consumer(归于某个顾客组)、多个 Producer、1 AdminClient
  • 1 Topic、1 Partition(Leader 副本在 Broker 1 上)
  • 当时 Controller 位于 Broker 0 上
  • Consumer 所属顾客组的 Coordinator 位于 Broker 0 中

架构图如下所示:

流程图 (6).jpg

下面我将结合上面的架构图,从集群办理、消费、出产这几个大的视角来解读一下

集群办理

集群办理是一个重要出题,由于 Kafka 集群需求办理大规划的 Broker 实例、顾客、出产者还有主题分区的音讯日志数据

ZK 事情监听

集群办理的作业首要是由 Controller 来完结的,而 Controller 又经过监听 Zookeeper 节点的改变来进行监听集群异动事情

Controller 进行集群办理需求保存集群元数据,监听集群状况异动状况并进行处理,以及处理集群中修改集群元数据的恳求,这些作业首要都是经过 Zookeeper 来完结的

当时示例集群中是 Broker 0 的 Controller 正在担任办理,监听 ZK 中的相关节点异动状况,而其他 Broker 中的 Controller 处于备用状况,监听 /controller 节点准备下一轮推举

ZK 目录结构

我整理了一下 Kafka 在 Zookeeper 中的目录结构,由于没有实测 Kafka 的一切集群功用,所以末级节点或许不完好有缺失,可是重要比较中心的 ZNode 我都掩盖到位了

整理出的 ZNode 树状结构图如下:

image.png

除了节点的称号,节点中还有 Kafka 序列化的 JSON 数据,部分节点的数据结构如下:

  • Partition 相关节点的值

/brokers/topics/test-topic/partitions/1/state

{
   "controller_epoch":1,
   "leader":0,// leader 副本地点的 broker id
   "version":1,// 代码里硬编码的一个值,始终是 1
   "leader_epoch":0,
   "isr":[// 已同步副本调集,Leader 副本包含在内
      0,
      1,
      2
   ]
}
  • Controller 相关节点的值

/controller 是个暂时节点,Session 超时过期等原因会导致此节点被删去

{
   "version":1,// 代码里硬编码的一个值,始终是 1
   "brokerid":0,// 当时是 Controller 的 Borker ID
   "timestamp":"1649930940915"
}

/controller_epoch 是个永久节点,数据会耐久化存储

1  // 值便是个递加的数字,表明推举周期
  • Topic Config 相关的值

此节点用于储存 Topic 级别的动态装备

/config/topics/test-topic

{
   "version":1,// 代码里硬编码的一个值,始终是 1
   "config":{
      "min.insync.replicas":"2"    // topic 级别的装备
   }
}

集群办理恳求转发

如上面的架构图所示,Broker 2 收到了 AdminClient 发送过来的 CreateTopicRequest 恳求,并没有进行处理,而是转发到了 Controller

碰到这类集群办理的恳求,Broker 都先对自身状况进行断定,不是 Controller 的状况下会对满意要求的恳求进行转发

一般是关于集群状况有修改的恳求会进行转发,关于读取集群状况的恳求则经过本地的元数据缓存来处理

副本办理

上面介绍的典型集群架构只要一个分区,三个副本,这儿拓宽成三个分区,九个副本的集群来扼要介绍一下 Kafka 副本办理的办法

流程图 (7).jpg

前面的音讯模型和架构图中里咱们现已了解了分区、副本的概念,这儿经过上面这张图整理一下分区和副本在集群中的分布联系

首先,同一个分区有多个副本,这儿设定的是 3 个,尽或许均匀分布在 Broker 中

其次,分区副本里有一个 Leader Replica,也便是领导者副本,担任分区音讯数据的读写,所以领导者副本在 Broker 之间也需求均匀分布,这样才能确保负载均衡

结合上面的图例,有几个点需求留意:

  1. 副本自身是没有专门的编号的,副本在哪个 Broker 上,对应的 Broker ID 便是它的编号(这儿也直接束缚了副本数量的最大值有必要小于 Broker 节点数量)
  2. 我这儿举例用绿色表明了从副本,假定的是已同步的状况,实践场景中会存在从副本未同步完结的状况

读写别离

读写别离是关于 Kafka 副本办理的一个抢手论题,Kafka 现在是支撑消费从副本音讯数据的,KIP-392 的提案便是关于这个机制

可是从上面的图中咱们也能够看出,你读取的从副本地点的 Broker 也是另一个分区的领导者副本地点的方位,大多数场景下运用这个功用只会导致抢手 Broker 的呈现,并承当数据同步推迟的价值,并不能到达咱们减轻领导者副本负载的意图

这个提案改善这个小功用点首要是为了处理跨数据中心/机架布置的场景下,尽或许从本地数据中心消费数据,下降网络通讯的成本开销,进步数据吞吐量

别的一点需求留意的是,Broker 的分区副本同步只能从领导者副本消费音讯进行拉取,无法从其他从副本获取数据,支撑读写别离的是客户端顾客

消费

消费的流程咱们只评论的是运用了 Kafka 供给的顾客组办理机制的顾客,关于手动办理消费进展的状况这儿不予评论

音讯消费的大体流程是:

  1. 衔接到任意 Broker,获取集群元数据
  2. 经过上一步的元数据,找到自己所属 Coordinator 地点的 Broker
  3. 参加顾客组,获取分区消费计划
  4. 获取相关分区消费进展,从上次消费的当地开端继续拉取音讯,一同本地保存消费进展
  5. 异步提交分区本地消费进展到 Coordinator

上面的架构图中蓝紫色的箭头展现了这样的音讯消费的流程次序

采用这样的流程去消费数据和 Kafka 的架构也是有密切联系的,由于消费的数据经过分区别布在整个集群的 Broker 中,所以需求获取整个集群的元数据了解自己需求获取的分区数据地点方位

相同在消费侧由于用了顾客组去进行负载均衡和容灾,所以顾客之间需求进行交流、和谐消费计划,可是顾客也是分布式运转的实例,所以需求 Broker 供给 Coordinator 这样的中介在顾客之间架起交流的桥梁

并发性

消费侧的并发性需求考虑两个问题:

  1. 音讯拉取到客户端
  2. 音讯偏移的提交和获取

前者支撑并发,可是后者则不然

从代码上看,同一个顾客组的消费进展是无法并发提交的,有加可重入锁维护顾客组的元数据目标,每次写入的时分都需求先获取到锁

// 针对顾客组元数据的许多操作都是在临界区中完结的
group.inLock {
    ...
}

愈加反直觉的是,消费进展的读取操作也是相同的一把锁维护,无法并发获取,具体原因不详,可是此锁的作用或许是:

  1. 维护正在运用中的顾客组不被删去
  2. 消费进展呈现改变(偏移过期被删去、分区扩容有新分区进展参加等),等候其他操作完结再履行

总的来讲针对一个顾客组的几乎一切操作都不支撑并发(读写都是),首要意图或许便是为了维护正在运用的资源不被意外删去

出产

音讯出产的大概流程是:

  1. 衔接到任意 Broker,获取集群元数据
  2. 发送音讯到指定的分区 Leader 副本地点的 Broker
  3. 其他 Broker 上的副本向 Leader 副本同步

上面的架构图绿色箭头展现了这个流程

在这个流程中音讯是经过集群元数据的提示,发往对应分区 Leader 副本地点的 Broker 上的,留意这儿不答应音讯在 Broker 之间进行转发

并发性

一句话总结:同一个 Topic 不同分区之间是支撑并发写入音讯的,同一个分区不支撑并发写入音讯

这很好了解,单个分区是临界资源,需求用锁来进行抵触检测确保同一时刻只要一批音讯在写入防止呈现音讯乱序或许写入被掩盖的状况

小结

这一节的架构解析选取了 Kafka 集群中比较重要的几个人物和主流程来进行叙说,可见为了完结前面所描绘的根本音讯模型,需求一系列的办理机制和谐、进行数据同步,还有容灾机制保障整个集群的有效运转

在前期的 Kafka 版别中,对 ZK 构成了强依靠,客户端都是经过直连 ZK 的办法去获取集群装备和更新自己的状况,不过后边的版别中逐渐进行了笼统层隔离宽和耦,现在需求客户端直接和 ZK 交互的当地现已没有了,都是和 Broker 打交道

这样的依靠解耦带来了简洁的接口笼统,下降了技能上的门槛,一同将部分责任从 ZK 搬运到 Kafka 还进步了服务的功用

别的,现在存在的一切需求经过 ZK 去干涉 Kafka 集群行为的办法,都能够经过 Admin API 或许其他接口去进行干涉,这种前期需求 Hack 的暴力干涉办法现已被彻底筛选

总结

这一部分介绍的是 Kafka 的架构,依照一般的剖析思路应该先用 CAP 理论对此体系做一个定性(CP AP CA?),然后再继续打开介绍

可是我这儿并没有急于给出这样的定性“结论”,究其首要原因是我认为这样的定性描绘其实不行精准,很容易使咱们陷入一种定式思想去看待 Kafka 并使得咱们忽视了躲藏在其内部的一些细节

已然这篇文章便是对 Kafka 内在架构和机制的拆解宽和读,一些细节不行忽视,所以咱们继续深化探求一下 Kafka 再去评论这个问题就能构成一个比较完好的观点了

中心机制

整个 Kafka Core 中权重最大、运用频率最高的三个人物是 Broker、Producer 和 Consumer,这几个人物的运用和咱们的事务开发也是休戚相关,对这些人物的中心机制进行深化了解对后续的事务开发、毛病排查是有很大协助

Broker

Broker 端是 Kafka 整个内部处理流程最杂乱的组件了,这当中的机制没有办法一个一个罗列出来具体说,我这儿挑选了 Controller 和 Broker 办理机制,还有副本办理中的高水位机制来进行介绍

之所以挑选这几个机制进行解读,是由于他们对协助了解集群毛病搬运进程中的行为、影响面有很大协助,其他机制都是围绕着这些中心的一些外围机制,是一些辅佐人物

Controller 推举

我下面画了一张集群毛病搬运的图,描绘的是 Controller 因网络、硬件毛病等原因下线,整个集群从头推举 Controller 的进程

流程图 (8).jpg

如图所示,整个 Controller 推举的进程分四个阶段进行:

  • 阶段 1:由于 Controller 和 Zookeeper 之间的会话由于超时、网络衔接断开等原因失效,导致暂时节点 /controller 被删去
  • 阶段 2:Broker 1 和 Broker 2 监听到了 /controller 删去的事情,触发了 Controller 的从头推举
  • 阶段 3:Broker 1 成功创立 /controller 节点并写入数据,Broker 2 检测到了新写入的 /controller 数据中止推举
  • 阶段 4:Broker 1 作为 Controller 初始化完结,向集群中的其他节点发送更新集群元数据的恳求,同步最新的数据

这个进程称之为「推举」其实有些不合适,由于这儿其实依据锁的一种选主机制,先抢到锁的获得资源运用权,由于后边 Kafka 推出了依据 KRaft 推举协议的 Controller,所以这儿想做一些特别阐明

留意,Controller 的推举之后往往伴随着 Broker 的下线,由于 Controller 的从头推举一般便是 Broker 失效引起的,下一节会介绍这其间的相关机制

Broker 上线下线

在线的 Controller 经过监听 /brokers 节点的异动状况处理 Broker 的上线、下线事情,这儿整理了一下整个事情处理的流程

流程图 (9).jpg

整个处理的流程仍是比较明晰的,分支不多,值得留意的点有几个:

  1. 异动数据是经过比对 Controller 中的元数据和 ZK 的数据差异核算出来的
  2. 这是个异步处理流程,在 ControllerEventManager 中用行列进行了解耦
  3. 针对 bouncedBroker 的处理办法是先移除,再增加
  4. KafkaController 中的 onBrokerStartup 办法履行了 Broker 上线后的存在 新增/离线 副本的分区进行领导者推举

Broker 的异动在集群中是一个十分重要的事情,由于其影响到了集群全体的可用性:

  • Coordinator 需求搬运到其他 Broker 上,不然与之绑定的顾客组无法正常运转,且搬运期间顾客组无法正常消费
  • 分区副本,尤其是领导者副本需求在 Broker 中从头分布,并且会触发分区领导者副本推举

上面两点我认为是集群 Broker 异动进程中比较中心的当地,由于 Controller 端处理完结 Broker 的元数据变更,后边的更新机制都是围绕这两个点进行

高水位更新

高水位是 Kafka 规划的一套用于盯梢从副本异步复制进展和确保数据一致性的机制

在架构部分扼要说了一下 Kafka 的副本办理中副本数据的分布状况,这儿进一步介绍一下对一个分区来说,是怎样经过高水位办理数据同步进展的

这儿咱们用一个三副本的分区的场景来介绍该场景下高水位的值是怎样更新到 4 的,如下图所示:

流程图 (10).jpg

留意:

  • 为了便利评论,这儿假设三个副本始终都在 ISR 中
  • 已写入领导者副本的音讯在写入时均满意最小已同步副本要求

更新规矩

在剖析这个更新流程之前,咱们先清晰一下更新规矩:

  1. 高水位的值便是长途副本状况中长途 LEO 的最小值,留意这儿不断定 ISR 是否满意最小已同步副本要求
  2. 从副本同步时拉取音讯的开端偏移,会被记录为此副本在 ISR 中的长途 LEO
  3. 从副本拉取音讯时,回来数据中包含当时最新的高水位值

整个高水位的更新流程都是依据上面这三条规矩去运转的,这三条规矩一同看能有点目不暇接,总结一下便是每次从副本建议音讯同步恳求的时分干两件事:

  1. 上报自己的拉取音讯起点,领导者副本将其作为 LEO
  2. 获取领导者副本的 HW 用于更新同步本地的 HW

流程解读

现在来看下这三条规矩是怎样运用的,更新流程如下:

  • 阶段1:副本 0 和 2 音讯都彻底同步,仅副本 1 存在 2 条音讯的推迟,这时分副本 1 宣布同步恳求,长途副本状况中对应的长途 LEO 更新为 4,本地 LEO 更新为 5
  • 阶段2:由于长途副本状况中的长途 LEO 发生改变,领导者副本的高水位更新为 4,随后从副本 2 宣布同步恳求,获取到了最新的高水位 4 并更新本地值,LEO 不发生改变
  • 阶段3:从副本 1 继续宣布同步恳求,长途副本状况的长途 LEO 此刻被更新为 5,恳求回来后获取到了最新的高水位 4 并更新本地值,一同长途 LEO 的更新引起领导者副本 0 高水位的改变,更新为 5,随后从副本 2 经过同步恳求获取到了改变后的值,高水位也随之更新为 5

后续重复以上流程,最终一切副本的高水位和 LEO 都会更新到 5

小结

这部分咱们介绍的是 Broker 端高可用、一致性方面的机制,其实服务端还要许多优异机制的完结值得继续深化挖掘和学习,比方主题分区副本的绑定机制、日志文件的办理等

文档后边的【学习资源】这一部分我供给了一些线索,对这方面感兴趣的能够继续深化去看

Producer

音讯发送机制

现在出产端的音讯发送是依据异步发送机制完结的,经过 RecordAccumulator 去做了解耦了音讯出产和网络恳求

这儿需求先阐明一下音讯出产恳求的结构:

image.png

留意一下当时版别的 Kafka 只答应每个分区有一个批次的音讯,不答应一个恳求发送多个批次

下面这张场景流程图描绘了 RecordAccumulator 两侧各自的处理流程,用户侧调用 send 办法之后,音讯被追加到 RecordAccumulator,异步线程轮询,满意条件之后调用网络客户端的 send 办法向 Broker 发送音讯出产恳求

流程图 (11).jpg

Java 版别的完结中,send() 回来的是一个 Future 目标,所以 send().get() 这样的用法就能起到同步阻塞等候音讯发送成功再回来的作用,可是本质上仍是在异步发送音讯

音讯乱序问题

咱们一般认为出产者发送的音讯总是能够确保分区有序,这是一种误解,由于这儿有一个陷阱,便是 max.in.flight.requests.per.connection 这个客户端网络装备

查阅 Kafka 的 官方文档 此装备的默许值是 5,表明一个衔接中能够一同有 5 个音讯批次在途,文档中也清晰指出了由于过错重试的联系,这种场景下音讯会乱序

所以,当咱们事务上对音讯次序有硬性需求的时分,这个点有必要引起注重

音讯分区机制

音讯分区机制能够认为是出产端的负载均衡机制,下面整理了一张分区核算的流程图,不同的分支对应不同的分区场景

需求留意的一点便是分区函数的入参不仅仅音讯的 Key,Topic、Value、Cluster(集群元数据)都能够作为该函数的输入信息去核算分区

流程图 (12).jpg

小结

这部分针对 Producer 的一些根底功用进行了一些介绍,对了解 Producer 客户端的运转现已满足

别的针对出产侧聊的比较多、比较深化的论题应该是分区音讯有序性、音讯幂等、精确一次语义等,这些问题独自打开都是一个大论题,在这儿就不一一评论了

Consumer

成员办理

顾客组是 Kafka 消费端完结负载均衡、动态扩容、毛病搬运的重要机制,此机制的运转和流通需求 Broker 端的 Coordinator 和消费端的 Consumer 经过树立长衔接进行交互和状况流通来完结此项作业

Coordinator 的定位

这儿插入一个小论题,那便是顾客怎样知道自己的 Coordinator 在哪个 Broker 上,核算的进程十分简明,便是依据顾客组名的 HashCode 对 __consumer_offset 主题的分区数进行取余,代码如下:

def partitionFor(groupId: String): Int = Utils.abs(groupId.hashCode) % groupMetadataTopicPartitionCount

核算出的分区领导者副本地点的 Broker 便是对应 Coordinator 的方位

留意,上述核算进程中所需的各种关于集群的信息,在获取集群元数据的阶段都缓存在了本地,这在本文的「架构-集群架构解析-消费」这一部分现已介绍过了

顾客组状况机

顾客组有一个状况调集,整个顾客组便是在这几个状况之间流通的,下面我用表格和状况机图例阐明这些状况怎样流通的,状况列表如下:

状况 前置状况 补白
Empty PreparingRebalance 此状况一同也是初始状况
PreparingRebalance Empty, CompletingRebalance, Stable
CompletingRebalance PreparingRebalance
Stable CompletingRebalance 搬运条件一般是 Coordinator 收到领导者发来的组同步恳求
Dead Empty, PreparingRebalance, CompletingRebalance, Stable 一般是 Coordinator 呈现搬运会导致组状况变成 Dead

状况流通图如下:

流程图 (13).jpg

上图展现的是一切或许的状况流通途径,对一个新创立的顾客组来说,契合预期的流通途径是 1 → 3 → 5,下一小节介绍重平衡机制的时分会具体阐明流通进程

此外,这个状况流通图中有一个风险的“死亡循环”,也便是 3 ⇆ 4 这两条途径组成的循环,下面介绍的重平衡机制与之相关

重平衡机制

重平衡机制是整个顾客组办理的重要机制,由于顾客组参加、退出、消费计划的分配这些中心功用根本都囊括其间

下面我将以一个新创立的顾客组为例,介绍一下重平衡机制,事例场景的状况如下:

  • Coordinator 位于 Broker 2 中,对应的顾客组成员只与其交互
  • 待参加的顾客组当时不存在
  • 三个顾客,且都能在规则的超时时刻内入组并成功
  • Consumer 0 最早建议入组恳求并被处理

整个重平衡分两个大的阶段进行,第一阶段申请入组,首要是等候一切待参加顾客组的成员入组并分配成员 ID,第二阶段组同步,首要是将顾客组领导者生成的分区消费计划向全组成员进行同步

重平衡的场景流程图如下:

流程图 (14).jpg

阶段一按时序联系细分了几个进程:

  • 进程一 Consumer 0 建议入组恳求
  • 进程二由于没有成员 ID 入组恳求被 Coordinator 回绝并回来了一个有效的成员 ID
  • 进程三 Consumer 0 带入进程二回来的成员 ID 再次入组并成功,Consumer 0 入组成功之后,其他成员连续建议入组恳求
  • 进程四 Coordinator 直接赋予其领导者身份,由所以第一个入组成功的成员

这一阶段整个顾客组状况从 Empty → PreparingRebalance,触发原因是进程三有顾客申请入组成功(进程一、二未触发原因是没有成员 ID 导致入组失败)

流程图 (15).jpg

阶段二依照时序联系分这么几个进程:

  • 进程一入组等候时刻完毕,向一切顾客发送入组成功成果
  • 进程二一切顾客向 Coordinator 发送组同步恳求,领导者 Consumer 0 发送的同步恳求中携带了依据入组成功成果核算的整个顾客组的分区消费计划
  • 由于进程二收到了顾客组的分区消费计划,所以进程三 Coordinator 向组成员广播了这个计划

这一阶段顾客组状况从 PreparingRebalance → CompletingRebalance → Stable,触发原因分别是:

  1. 入组等候时刻完毕
  2. 领导者建议了组同步恳求

除了新建的顾客组之外,已有的顾客组由于许多事情也会触发重平衡机制,并且整个平衡的进程和这儿的事例会有所区别

这儿举了个比方仅仅为了协助读者对整个重平衡进程有个大体的印象,了解整个进程中发生的首要流程,其他场景下的重平衡进程就不一一举例铺开叙说了

分区消费计划

分区消费计划的构成首要考虑两个进程:

  1. 消费计划的生成
  2. 消费计划的分发

进程 2 在上一节现已介绍过了,这儿就说一下进程 1

假如顾客入组成功之后被指定为了领导者,那么后续它发送的组同步恳求中就带入了现已生成好的分区别配计划

生成消费计划常见的战略是这两个:

  • org.apache.kafka.clients.consumer.RangeAssignor
  • org.apache.kafka.clients.consumer.CooperativeStickyAssignor

值得留意的是在 Kafka 的架构上消费计划是由顾客担任生成的,首要原因我想除了功用考量之外,还有一个原因便是为了更便利顾客自界说消费战略

不均衡分配问题

咱们一般说的分区别配战略默许是 RangeAssignor,该战略依照主题进行分配,尽量确保每个主题的分区在顾客之间尽量平均绑定

不过这种分配战略在完结上有些问题:

  1. 对顾客列表进行了排序
  2. 排序后的次序,按主题进行循环分配

由于对顾客做了排序再分配,会导致排序后的最终一个顾客总是分配到比其他顾客少的分区,构成不均衡的分配计划

流程图 (16).jpg

每一个 Topic 的分配都是不均衡的,这个偏差会逐渐累积

其他的分配战略或多或少都有相似的问题,挑选事务上运用的分配战略时需求留意这一点

心跳保活机制

顾客参加顾客组之后,还需求保活机制保持其组成员的这个身份,保活首要经过两条途径来进行:

  1. 客户端每次 poll 测验拉取音讯,Consumer 中运转在异步线程的 ConsumerCoordinator 会断定两次 poll 的时刻距离是否超出 max.poll.interval.ms 设定的值,超越则断定失效建议主动离组恳求
  2. 异步线程定时发送心跳包,距离超越session.timeout.ms 则服务端断定失效,强制除掉出顾客组

假如两者之一失效顾客会被移出顾客组并触发重平衡机制,整个进程和上面介绍的重平衡机制相似

要留意上面两条途径一个是客户端本地断定,另一个是服务去断定的,第一条由所以客户端的完结,有些言语的客户端或许没这个机制

小结

顾客组也是一个独立的分布式服务集群,运转着事务代码,靠 Kafka 进行分布式场景下的和谐和数据耐久化作业

正由于消费端也是一个分布式体系,所以分布式场景下的一切问题在这儿都相同存在:出产端分区、消费端分区别配机制呈现问题都或许引起数据歪斜;顾客数量上去总会有节点失效的状况呈现,需求对应的灾备机制进行处理;顾客之间依靠中心化的服务去和谐调度,进行消费使命的分配,中心化服务的失效相同会引起顾客组的毛病

事务场景的应战

当然 Kafka 在规划之初对需求面对的应战做了充沛的规划和论证,可是面对实在的运用场景它的体现终究怎样?

在咱们平时的事务开发场景里,运用到 Kafka 首要是做一个分布式微服务下的异步事情的出产和消费,并且绝大部分事务不会有十分大的音讯吞吐量,在这些场景下 Kafka 的功用体现优异,对事务来说无法感知到功用瓶颈

可是在极点场景下,比方大数据剖析的场景中,体系数据吞吐量很大,Kafka 集群中的各个组件都在承受巨大压力,任何一个单个组件的毛病失效或许行为异常,都或许在集群内大规划分散导致雪崩,引起体系功用的急剧下降,甚至是毛病时效无法供给服务

至于或许构成这些不契合预期体现的原因,从上面介绍的架构、机制中咱们能够找到这些问题的答案

ZK 的巨大压力

在 1000+ Broker 的场景下,主题、分区、顾客组的数量巨大,需求在 Zookeeper 中保存许多的数据,并且这么多的节点在集群运转的进程中会频频发生节点和数据的改变,触发事情告诉 ZK 客户端

这儿有个事例 出产毛病|Kafka音讯发送推迟到达几十秒的罪魁祸首竟然是… | HeapDump功用社区 共享的便是 ZK 对客户端恳求的处理推迟过高,心跳包无法及时处理引起 Controller 和 Broker 大面积掉线,音讯无法写入

ZK 是强一致性的存储体系,写入功用欠安,面对如此高频率的写入恳求自然是很难敷衍的过来,是束缚集群规划进一步扩张的重要条件

因而为了打破这一束缚,进一步开释 Kafka 作为高功用音讯引擎的潜力,在新发布的版别中自行完结了一套分布式一致性协议 KRaft 并支撑 Controller 独立布置

图片来历:developer.confluent.io/learn/kraft…

现在 KRaft 版别的 Kafka 在出产环境上落地的事例很少,后续我会继续注重新机制给 Kafka 带来的改变和功用进步

别的,这儿的举例仅仅用了一个比较夸大的集群规划,受限于硬件装备和软件版别等原因,实践的集群或许在几十个 Broker 又或许 Topic 十分多的场景下就会呈现 ZK 的功用瓶颈

不堪重负的 Controller

前面的集群架构部分咱们现已了解到,一切的 Broker 中都有一个 Controller 人物,可是一同只要一个对外供给服务,这儿评论一下这个集群仅有的 Controller 的负载问题

相同是考虑在 1000+ Broker 集群的场景下,Controller 地点的 Broker 负载会比其他 Broker 大,由于要处理整个集群规划内一切集群办理相关的恳求,那么这个 Broker 就很或许由于负载过大导致节点失效,引起 Controller 推举和毛病搬运

在小规划的集群中这样的毛病搬运能够很快速,价值很小,可是在咱们现在评论的场景中集群元数据许多,一同伴随着许多的主题和分区音讯数据,整个毛病搬运的价值十分大

搬运进程中或许呈现的一些异常状况:

  • Controller 推举进程时刻长,推举期间无法履行新建主题、分区扩容等操作
  • Broker 之间进行分区副本数据的搬运,许多的文件读写导致页缓存大规划失效,Broker 无法读取到到页缓存,也参加到了频频的 IO 操作中进一步恶化 IO 功用
  • 没有 Controller 导致集群元数据无法及时更新,导致客户端获取到无效的数据,无法正常作业

Controller 在集群中的方位十分重要,Kafka 及其相似的音讯体系都对这一个组件做了许多重构和优化,构成了不同的处理计划:

  1. 能够将集群中的几个 Broker 独立出来,进步硬件装备,专门担任 Controller 推举
  2. BMQ [3] 对 Kafka 的这部分功用进行了重构

不安稳的顾客

在这儿咱们考虑一下实践消费场景下的状况,假设有一个 100+ 顾客的消费组

前面咱们现已介绍了一种场景下的重平衡机制,这儿需求评论关于重平衡对事务的影响,由于建议重平衡之后,顾客组就无法继续消费数据了,必需求比及顾客组从头进入安稳状况才能够继续消费

理想状况下,顾客成功入组之后就能继续消费,安稳运转,可是实践场景中面对如下应战:

  • 初次入组,由于不同顾客发动速度有差异,导致 99 个顾客成功入组之后,最终一个顾客申请入组触发重平衡(默许是等候 3s 进入 PrepareRebalancing)
  • 顾客消费进程中,由于数据歪斜部分顾客负载高,因 GC 等原因下线或心跳超时,触发重平衡
  • 顾客组运转进程中,发现消费进展跟不上,故对顾客组扩容触发重平衡

重平衡的价值很大,需求等一切顾客中止消费,然后敞开申请入组、组同步的这个流程,整个重平衡期间顾客组无法消费将加重音讯消费的推迟

所以在这种顾客数量多的状况下,确保每个顾客能够安稳运转十分重要,防止因 GC 或许网络抖动等内外因素触发重平衡

虽然 Kafka 供给了顾客组这样的机制去协助完结消费端的负载均衡和弹性扩容,可是这种扩容也是有鸿沟的,消费集群的规划也不是能够无限扩张的,确保消费集群的安稳性是个很大问题

针对消费场景的重平衡问题,比较常见的做法是绕过这套机制自行办理分区的消费,比方我接触过的 Spark 和 Flink 大数据核算框架便是首要运用自行分配绑定分区消费,并且不运用 Kafka 供给的音讯偏移办理机制或仅作为辅佐手段

事务上也能够参阅这种计划去完结一套消费计划的办理机制,对呈现毛病的顾客予以告警和及时介入,隔离毛病节点和对应的分区,不要影响其他分区的正常消费

至于 Kafka 供给的顾客组静态成员的机制,这个事务事例不多,就不做介绍了

不行靠的代码

中心机制中介绍了出产者的音讯分区函数,这是出产端负载均衡的重要机制,最常见的无 Key 或许运用哈希值核算分区的场景下,Key 总是能在分区中均匀分布

实践事务场景中分区函数不一定依照咱们预期的行为向 Broker 分发音讯,由于代码问题仍是或许导致Key 的核算不契合预期,分区数据发生歪斜,引起部分 Broker 负载过高

由于在 Kafka Core 集群的架构里存储和核算没有别离,这种场景下由于存储导致的压力无法向其他 Broker 均摊,反而会拖累整个 Broker 一同挂掉

此外,除了 Key 分区引起的数据歪斜之外,过大的音讯体也或许构成问题(比方把整个文件当成音讯体发送),假如由于代码过错向某个分区继续发送比较大的音讯体构成数据歪斜(实践状况没有这么夸大,由于服务端对单批次的音讯最大值有束缚,默许是 1048588 Bytes ≈ 1MB)

假如是把 Kafka 当成文件体系来运用的确或许呈现这个问题,因而大文件的异步消费最好是只传递文件的元信息

毛病搬运带来的体系冲击

前面几个场景现已屡次提到了毛病搬运场景下的种种问题,这儿做个总结性质的陈说

毛病搬运机制处理的是可用和主动化的问题,确保部分节点失效的状况下,体系全体是可用的,能够继续对外供给服务,而主动化能够确保毛病的第一时刻有一个应对机制,下降对事务的影响,给后续的人工处理和介入争取时刻

因而在毛病搬运的场景下,咱们有必要考虑由于负载在节点间的从头分配,导致的节点负载改变,优化整个搬运进程,进步整个服务的可用性,防止由于毛病搬运导致服务的严峻降级,影响用户体验,或许构成虽然服务还活着可是产品现实不行用的局面

毛病搬运是从体系失衡进入到另一个稳态,这个搬运进程必定是对原体系有冲击的,经过一段时刻的从头平衡之后再回到安稳状况

在主动化的机制之外,还需求树立事务上的呼应机制,提前准备好灾备计划,以便呈现毛病时能够及时人工介入

毛病搬运是一个十分值得深化评论的技能论题,这篇文档对这个问题无法进行太深化的探求,这儿就浅谈几句

总结

Kafka 诞生在云原生的概念尚未呈现的时代,从存储底层开端一步一步构建出一套自成一体的分布式音讯体系,成为业界标准的音讯引擎

经过对 Kafka 架构和中心机制的深化了解,咱们不难发现为了完结这个音讯引擎的高可用、高功用和强一致,能够说各方面都做到了极致优化,并且每个优化的环节都是彼此相关,环环相扣,甚是巧妙

比方 Kafka 音讯索引的规划便是一个好的比方,不止是进步了经过音讯偏移查找的速度,更是利用到这个信息去完结了音讯消费阶段的零复制,能够说是做到了两全其美,功用加倍的作用

别的,Kafka 是分布式体系的一种工程完结,不是纯理论的理想模型,假如依照 CAP 理论对其进行生搬硬套一定是行不通的,这也是文章的前面我都没有用这个理论先去解说一番的原因

依照常见的理论解说,Kafka 应该是 AP 体系,用音讯分区进行负载均衡进步功用,用副本机制确保 Broker 失效的场景下的可用性,副本之间的音讯是最终一致性的联系

很显然,这样的 AP 体系是无法在线上运用的(想想看 unclean.leader.election.enable 参数线上集群能用否?),副本之间是纯异步复制,随时会有未同步副本上线对外供给服务,没有人乐意承当这种由于数据一致性问题带来的音讯永久丢掉风险

所以 Kafka 在规划和完结的时分便是在 CAP 三角中结合自己体系的运用场景做出了取舍,构成了有限的分区容错(分区失效服务会短暂不行用)、全体可用(集群能够部分失效)、弱一致性(高水位和副本推举机制)的或许三角,各方面都有兼顾

你认为的 AP 体系,其实是……

也正是由于种种现实原因的束缚,Kafka 的规划和完结上注定有不完美的当地,也有许多的历史遗留问题,这些问题咱们文章的前面也都有提到,这些问题或大或小,正是这些问题的存在进一步推动了 Kafka 自身的迭代进化,也催生出了其他的或许性

Pulsar 这样的云原生音讯体系便是在架构上对 Kafka 核算存储一体的架构做了改善,存储核算别离,充沛利用了当今云原生环境的带来的扩展性优势,成为当下抢手的项目

此外还有字节自研的 BMQ 这样的音讯中间件,相同对 Kafka 架构还有内部中心机制的完结上做了重构和一些优化,去支撑自己的事务需求

Pulsar 的架构图如下,能够显着看到集群架构中的存储与核算别离的规划,担任存储的 Bookie 是独立的集群,与音讯引擎解耦,BMQ 也有相似的规划,只不过用的组件不同

总的来说 Kafka 作为一个出道十几年的项目,久经考验,生命力顽强,的确是音讯体系的经典规划

学习资源

源码学习

入门指南

Kafka 是 Java 和 Scala 言语混合的项目,现在 IDEA 对这种项意图支撑度最好,想要学习源码的话引荐用这个 IDE,省去许多处理环境问题的时刻

开端阅览服务端代码的话,引荐从两个当地开端:

  • KafkaApis 这个类是各种外部恳求 Handler 的入口,从这儿能看到 Kafka 各种接口的完结
  • KafkaServer 这个类是服务端 Broker 对应的完结类,从这儿作为入口能学习到整个服务端发动的流程

阅览客户端代码的话,Producer 能够注重 RecordAccumulator 这个类,这是解耦本地音讯缓存和网络发送线程的纽带

Consumer 应该注重 ConsumerCoordinator 的完结,关于顾客组办理客户端的完结都在这儿,想了解重平衡等客户端中心机制都需求在这儿找答案

代码导航

我把源码中呈现的重要人物依照类名做了整理,介绍了首要责任,供咱们学习源码的时分参阅

image.png

KIP

KIP 是 Kafka Improvement Proposal[5] 的缩写,一些严重的功用变更都是用这样的改善提案的办法建议的,这些提案对了解一些内部机制完结的动机和进程有十分大的协助,归于十分优质的第一手学习材料

这篇文章中引证了许多经典的 KIP,这儿整理了一个列表出来便利后续对社区动态的跟进和源码的学习

KIP 编号 提议内容 补白
KIP-63 答应顾客从后台线程发送心跳包
KIP-82 音讯增加头部信息(Headers) 除了音讯体之外,答应增加键值对办法的头部信息,用于路由或许过滤等功用
KIP-106 unclean.leader.election.enabled 装备的默许值从 true 变为 false
KIP-134 推迟初次初始化顾客组的重平衡操作
KIP-392 答应顾客从最近的副本拉取数据 顾客的界说不含从副本向领导者副本的消费人物
KIP-500 移除对 Zookeeper 的依靠,依据 Raft 协议开宣布一套新的推举协议进行集群元数据的办理
KIP-516 主题仅有标识符 阅览 Motivation 的部分了解为什么要增加这个标识符即可,其他的技能细节不是特别重要了
KIP-555 Kafka 办理工具中废弃与 Zookeeper 的直连功用
KIP-584 集群功用版别操控 用于处理集群滚动晋级,以及不同版别客户端兼容的场景下的一些问题
KIP-630 Kafka Raft 快照 归于 KIP-500 的后续功用性 KIP
KIP-631 依据推举的 Kafka Controller 归于 KIP-500 的后续功用性 KIP

其他

  • Kafka 官方文档[1] 是最威望的第一手材料,平时用来当手册查询各种装备的文档十分便利
  • BMQ 的规划文档[3] Motivation 的部分指出了 Kafka 作为大规划音讯行列集群的问题,整个规划文档便是对 Kafka 的再思考和重构,是从另一个视点审视 Kafka 的好材料
  • Why BMQ [4] 这篇文档针对不同实践运维场景,将 Kafka 和 BMQ 进行比照,指出了各自优缺点

参阅文献

  1. Kafka 官方文档
  2. Apache Kafka® Internal Architecture – The Fundamentals
  3. BMQ 规划文档
  4. Why BMQ
    9.Kafka Improvement Proposal (KIP)

参加咱们

扫码发现职位 & 投递简历:

image.png

官网投递:job.toutiao.com/s/FyL7DRg