<br/>
Apache Kafka 是一种分布式音讯零碎,由 Scala 语言编写而成。
Kafak 基本概念
message
message 是 Kafka 中最根本的数据单元,它由 key 和 value 两局部形成,KV 都为字节数组。
Kafka 会依照肯定的策略,将音讯依照 key 值路由到指定的 partition 中,从而保障 key 雷同的 message 全副写入同一 partition 中。
value 是 Kafka 真正传递的业务数据。
topic、partition、broker
topic 是 Kafka 中的一个逻辑概念,kafka 集群中能够定义多个 topic。
在应用的时候,producer 和 consumer 会约定好一个 topic 名称,producer 产生的 message 会写入到该指定的 topic 中,consumer 会从该指定的 topic 中读取 message。
topic 能够看做为一个 message 通道,连贯多个 producer 和 consumer,如下图所示:
在 topic 这个逻辑概念中,kafka 做了进一步的拆分,将一个 topic 分为一个或多个 partition(一个 topic 至多有一个 partition),如下图所示:
从上图能够看出,当 message 在被 producer push 到一个 partition 的时候,都会被调配一个 offset 编号,offset 是这条 message 在这个 partition 中的惟一编号。
通过 offset 编号,kafka 就能够保障一个 partition 内的 message 是有序的,咱们能够认为 partition 是一个用来记录有序 message 的存储。
在生产环境中,不同 topic 须要反对的流量大小有所不同,也就是说,topic 须要横向扩大的能力,kafka 就是通过 partition 来实现的。
同一 topic 的不同 partition 会调配到不同的物理机上,partition 是 topic 横向扩大的最小单位,一个 partition 中存储的这一组有序 message 没法存储到多台机器上。
常见的 kafka 架构如下图所示:
从上图中咱们能够看到,多个 partition 位于同一个 broker 中,broker 其实就是一个 kafka server 服务,kafka 集群是由多个 broker 形成的。
咱们能够通过减少 partition 以及 broker 的形式,进步 topic 的吞吐量。
这里的 broker 是 kafka 的外围之一,主要职责有上面外围三个:
- 接管 producer 发送过去的 message,并保留到磁盘中
- 解决 consumer 的申请
- 解决集群其余 Broker 的申请,依据申请类型进行相应解决并返回响应。
<br/><br/>
log
理解了 partition、topic、broker 这个三个宏观概念之后,咱们向宏观方向进一步剖析。
partition 在逻辑上对应着一个 log,当 producer 向 partition 推送 message 的时候,kafka 实际上是将 message 写入到 partition 对应的 log 中。
log 由多个 segment 形成,log 和 segment 都是逻辑上的概念。实际上,log 对应 磁盘上的一个文件夹,segment 对应 log 文件夹下的一个 segment 文件和一个 index 文件。
在写入 partition 时,咱们只会写入最新的 segment 文件和 index 索引文件,当这个 segment 文件收缩到肯定大小之后,会创立新的 segment 文件持续写入,旧的 segment 文件就不再写入了。
之所以这么设计,为了避免出现超大的单个 segment 文件,也是为了采纳程序 IO 的形式写入,所以只向最新的 segment 文件追加数据。
再来看 index 文件,它是 segment 文件的一个 稠密索引 的文件,在 kafka 运行过程中,会将 index 文件内容映射到内存中,进步索引速度。
<br/><br/>
replica
为了进步分布式系统的可用性,保障的数据完整性和安全性,咱们个别会对数据进行备份,kafka 也是这个套路。
在 kafka 中,partition 个别会有多个 replica(正本)(至多一个 replica),同一个 partition 的不同 replica 中的 message 是截然不同的。
partition 中的 replica 尽管数据一样,然而还是有角色上的辨别:一个 partition 下的多个 replica 中,有一个是 leader replica,其余的 replica 都是 follower 角色。
所有的读写申请都由 leader replica 进行解决的,其余的 follower replica,仅仅是定期从 leader replica 拉取新写入的 message 到本地,并同步更新到本人的 log 中。结构图如下图所示:
正如上图所示,同一 partition 的不同 replica 会被调配到不同的 broker 上。这样,当 leader replica 所在的 broker 宕机之后,kafka 从残余的 follower replica 中选举出新的 leader replica,而后由新 leader replica 持续对外提供读写服务。
<br/><br/>
ISR 汇合
上面咱们持续深刻聊一下 replica。
kafka replica 中有个叫做 “ISR” 的概念,全称为 “In-Sync Replica”,它示意的是一个 replica 汇合,该汇合中的 replica 必须满足上面两个条件:
- replica 所在 broker 必须与 Zookeeper 集群放弃连贯。
- replica 中最初一条 message 的 offset 与 leader replica 中的最初一条 message 的 offset 之间的差值,不能超出指定的阈值。
kafka 集群会为每个 partition 保护一个 ISR 汇合,kafka 写入 message 的性能与 ISR 汇合有十分亲密的分割:在 leader replica 收到写申请的时候,首先是由 leader replica 进行解决实现长久化到本地的 log,之后 follower replica 定期申请 leader replica,拉取新写入的 message,并同步到 follower replica 本地的 log 中。
当然,follower replica 的定期同步申请绝对于 leader replica 的写入操作来说,会有肯定的提早,这就会导致 follower replica 中存储的 message 稍微落后于 leader replica,然而只有未超出指定阈值都是能够容忍的,这些 follower replica 也就是处于 ISR 汇合中。
如果一个 follower replica 呈现宕机、长时间 GC、网络故障等等异样申请,导致其长时间没有与 leader replica 进行数据同步,也就是,导致 follower replica 不再满足条件,而被踢出 ISR 汇合。
在 follower replica 从上述故障中复原之后,会从新开始与 leader replica 进行同步,当 follower replica 追上 leader replica 时(即两者最初一条 message 的 offset 的差值小于指定阈值),该 follower replica 会被重新加入到 ISR 汇合中。
<br/><br/>
HighWatermark、Log End Offset
HW(HighWatermark)和 LEO(Log End Offset)与下面的 ISR 汇合严密相干。
HW 记录的是一个非凡的 offset 值,在 consumer 拉取 message 的时候,只能拉取到 HW 之前的 message,HW 之后的 message 对 consumer 来说是不可见的。
与 ISR 汇合相似,HW 也是由 leader replica 治理的。当 ISR 汇合中全副的 follower replica 都同步了 HW 对应的 message 之后,leader replica 会递增 HW 值。
正因为 HW 之前的 message 同时存在于多个 replica 中,即便 leader replica 呈现宕机或是磁盘损坏等故障,这些 message 也不会呈现数据失落(follower replica 会从新竞选为 leader replica,并提供读服务),所以 kafka 认为 HW 之前 message 处于 “ 已提交 ” 状态。
LEO(Log End Offset)是所有的 replica 都会有的一个 offset 标记,它用来记录追加到以后 replica 中的最初一个 message 的 offset 值:
- 当 leader replica 接管到 producer 发送的 message 时,leader replica 的 LEO 标记会减少。
- 当 follower replica 胜利从 leader replica 中拉取 message 并更新到本地 log 时,follower replica 的 LEO 也会减少。
理解了 HW 和 LEO 的基本概念之后,咱们这里用一个动静的形式来阐明 HW 和 LEO 是如何一起工作的,如下图所示:
- 首先来看 producer,它向咱们关怀的一个 topic 中的一个 partition 发送一条 message。
- 该 message 写入 leader replica 时,被调配的 offset 为 5,同时 leader replica 会将其 LEO 值从 4 批改为 5,此时 leader replica 的 HW 仍旧为 4。
- follower replica 从 leader replica 拉取 message 并同步到本地 log,follower replica 会将本身的 LEO 从 4 批改为 5。
-
当 ISR 汇合中所有 replica 都实现了对 offset=5 的同步,leader replica 会将 HW 标记从 4 批改为 5。
实现上述操作之后,consumer 再次来拉取 message 的时候,就能够看到 offset 为 5 的 message 了。
<br/><br/>复制方案设计
介绍完 replica 的根底知识点之后,咱们再深刻了解一下 replica 设计思维。如前文所说,冗余备份是分布式存储中常见的计划之一,备份的罕用计划有同步复制和异步复制两种:
- 同步复制的含意是所有 follower replica 都要复制完一条 message 之后,该 message 才是 “ 已提交 ” 状态。
- 异步复制的含意是 leader replica 收到 producer 发送的 message 之后,会立即更新 HW,也就是认为该 message 处于 ” 已提交 ” 的状态。之后,follower replica 会异步的从 leader replica 中同步 message。
上面来看说这两个复制计划的问题:
- 对于同步复制计划来说,一旦有一个 follower replica 呈现故障或是长时间 Full GC,无奈同步 message,就会导致 HW 无奈更新,进而导致 message 无奈提交,consumer 也就获取不到音讯。此时的故障 follower replica 会导致整个分布式系统不可用。
- 对于异步复制计划来说,尽管防止了同步复制计划一个故障点拖垮整个集群的问题,但存在数据失落的危险。例如,在一个集群中,所有的 follower replica 的同步速度都比较慢,并且其中存储的 message 量都远远落后于 leader replica。如果此时 leader replica 产生宕机,则从新选举出的 leader replica 中没有原 leader replica 的全副 message,就会造成数据失落,另外,此时的一些 consumer 可能生产了这些失落的 message,而且没人晓得这些失落的 message 是什么,整个零碎的状态就不可控。
kafka 的 replica 和 ISR 汇合设计,衡量了同步复制和异步复制两种计划:
- 当某个 follower replica 的同步落后于 leader replica 太多的时候,kafka 将其断定为可能呈现故障的 replica,会将其踢出 ISR 汇合。因为 message 的提交,只关注 ISR 汇合中的 replica,所以这个慢速同步的 replica 并不会影响整个零碎的性能。
- 当 leader replica 呈现宕机等异常情况的时候,kafka 会优先从 ISR 汇合中选举新的 leader replica,新 leader replica 中蕴含了 HW 标记之前的全副 message。因为 HW 之后的 message 处于 ” 未提交 ” 状态,从 kafka 集群之外看,是感知不到 leader replica 的切换,数据也不会失落。
<br/><br/>
Retention Policy & Log compaction
对 kafka 有肯定理解的同学可能晓得,无论 message 是否曾经被 consumer 生产,kafka 都会长工夫保留 message 信息,这种设计是为了不便 consumer 回退到某个 offset,并从新开始生产。
然而,kafka 毕竟不是数据库,不应该始终保留历史 message,尤其是那些曾经确定不会再应用的历史 message。咱们能够通过批改 kafka 的 retention policy 配置(保留策略)来实现周期性清理历史 message 的成果。
kafka 默认提供了有两种 retention policy:
- 依据 message 保留的工夫进行清理的策略,其具体含意是:当一条 message 在 kafka 集群中保留的工夫超过了指定阈值,就能够被后盾线程清理掉
- 依据 topic 占用磁盘大小进行清理的策略,其具体含意是:当 topic 的 log 小大于一个阈值之后,则能够开始由后盾线程删除最旧的 message。
kafka 的 retention policy 能够针对全副 topic 进行配置,还能够针对某个 topic 进行非凡的配置。
除了 retention policy 之外,kafka 还提供了 log compaction(日志压缩)来缩小磁盘占用量。咱们晓得 message 由 key 和 value 两局部形成,如果一个 key 值对应的 value 值一直被更新,且 consumer 只关怀最新的 value 值,那么咱们就能够开启 log compaction 性能来压缩日志,外围原理是:
kafka 会启动一个后盾压缩线程,定期将 key 雷同的 message 进行合并,只保留最新的 value 值。
下图展现了一次 log compaction 的工作过程:
<br/><br/>
controller
正如后面介绍,kafka 集群是由多个 broker 形成的,kafka 集群会选举出一个 broker 来负责 controller。
controller 次要是负责管理 partition 的状态、治理 partition 下 replica 的状态以及监听 Zookeeper 数据的变更等。
controller 是一主多从的实现形式,所有 broker 都会监听 controller leader 的状态,当 controller leader 呈现故障时,会从新选举新的 broker 成为 controller。
<br/><br/>
consumer
consumer 的次要工作是从 topic 中拉取的 message,并生产 message 实现本身的业务逻辑。
consumer 中保护了一个 offset 信息,用来记录以后 consumer 生产到 partition 的哪个地位(offset)。
由 consumer 来保护 offset 是为了缩小 kafka broker 保护 consumer 状态的压力,尤其是在 broker 呈现故障或延时的时候,就会导致生产状态失落或是影响 consumer 的生产。另外,这样设计也让 consumer 依照本人的需要指定 offset 进行生产,例如跳过某一部分 message 或是反复生产某些 message。
<br/><br/>
consumer group
kafka 中的多个 consumer 能够组成一个 consumer group,consumer group 才是生产 kafka message 的根本单位。
一个 consumer 只能属于一个 consumer group。在一个 consumer group 外部,会保障其生产的 topic 的每个 partition,只会被调配给该 consumer group 的一个 consumer 进行生产。当然,不同 consumer group 之间不会相互影响。
依据 consumer group 的这个个性,咱们能够将每个 consumer 独立组成一个 consumer group,这样就能够实现播送的成果(即一个 message 被多个 consumer 同时生产)。
如果要实现独占生产的成果,能够将指标 topic 的全副 consumer 放入一个 consumer group 中,这样的话,就能够保障每个 partition 只有一个 consumer 生产。
下图展现了一个 consumer group 中 consumer 与 partition 之间的对应关系,其中的 consumer0 和 consumer1 别离负责生产 partition0 和 partition1 两个 partition,consumer2 负责生产 partition2 和 partition3:
consumer group 除了提供了独占和播送两种生产模式之外,consumer group 还实现了程度扩大和故障转移。在上图 consumer2 的解决能力不足以生产两个 partition 的时候,咱们能够通过向 consumer group 中增加新 consumer 的形式,重新分配 partition 与 consumer 的映射关系,如下图所示:
在增加 consumer3 之后,consumer2 只生产 partition2 中的 message,partition3 则重新分配给了 consumer3 来生产。
接下来再看 consumer group 故障转移的场景,在 consumer3 产生故障的时候,consumer group 也会重新分配 consumer 与 partition 的映射关系,如下图所示,consumer2 从新接手 partition3:
依据下面形容的 consumer 与 partition 一对多 (或一) 的准则,consumer group 中 consumer 的数量并不是越多越好,当一个 consumer group 中的 consumer 数量超过 topic 中 partition 的数量时,这会导致有 consumer 调配不到对应的 partition,从而造成这些 consumer 闲暇。
<br/><br/>
总结
本课时咱们重点介绍了 kafka 的基本概念,次要波及到上面几局部:
- message 的形成
- kafka 中 topic、partition、broker 三大外围概念和它们之间的关系
- log 这个逻辑概念以及对应的物理实现,其中包含 segment 文件、index 稠密索引文件的介绍
- replica 与 partition 的关系,以及 replica 主从设计的相干探讨
- ISR 概念的介绍
- HighWatermark、Log End Offset
- 复制方案设计
- Retention Policy & Log compaction
- controller
- consumer、consumer group
感激同学们的观看,课程的相干文章和视频还会放到
- 微信订阅号: 杨四正
- 抖音:杨四正
- B 站:kafka 基本概念