Kafka基础与核心概念

2022-12-01 16:49:23 浏览数 (2)

本文,我们将试图回答什么是apache kafka。

kafka是一个分布式流平台或者分布式消息提交日志

分布式

Kafka 由一个或多个节点组成的工作集群,这些节点可以位于不同的数据中心,我们可以在 Kafka 集群的不同节点之间分布数据/负载,并且它天生具有可扩展性、可用性和容错性。

流平台

Kafka 将数据存储为可以用不同方法处理的连续记录流。

提交日志

当您将数据推送到 Kafka 时,它会将它们附加到记录流中,例如将日志附加到日志文件中,该数据流可以“重放”或从任何时间点读取。

kafka是不是消息队列

它当然可以充当消息队列,但不限于此。 它可以充当 FIFO 队列、发布/订阅消息系统、实时流媒体平台。 并且由于 Kafka 的持久存储能力,它甚至可以用作数据库。

综上所述,Kafka 通常用于实时流数据管道,即在系统之间传输数据、构建转换连续流动数据的系统以及构建事件驱动系统。

我们现在将进入核心 Kafka 概念。

消息

消息是 Kafka 数据的原子单位。 假设你正在构建一个日志监控系统,你将每条日志记录推送到 Kafka 中,你的日志消息是一个具有这种结构的 JSON。

代码语言:javascript复制
{
  "level" : "ERROR",
  "message" : "NullPointerException"
}

当您将此 JSON 推送到 Kafka 时,您实际上是在推送 1 条消息。 Kafka 将这个 JSON 保存为字节数组,而那个字节数组就是给 Kafka 的消息。 这就是那个原子单元,一个具有两个键“level”和“message”的 JSON。 但这并不意味着你不能向 Kafka 推送任何其他内容,你可以向 Kafka 推送 String、Integer、不同模式的 JSON 以及其他所有内容,但我们通常会将不同类型的消息推送到不同的主题。

消息可能有一个关联的“key”,它只是一些元数据,用于确定消息的目标分区。

主题

Topic,顾名思义,就是Kafka中消息的逻辑分类,是同类型数据的流。 回到我们之前的日志系统示例,假设我们的系统生成应用程序日志、入口日志和数据库日志,并将它们推送到 Kafka 以供其他服务使用。 现在,这三类日志在逻辑上可以分为三个主题,appLogs、ingressLogs、dbLogs。 我们可以在 Kafka 中创建这三个主题,每当有应用日志消息时,我们将其推送到 appLogs 主题,对于数据库日志,我们将其推送到 dbLogs 主题。 这样我们就在消息之间进行了逻辑隔离,有点像用不同的表来保存不同类型的数据。

分区

分区类似于数据库中的分片,是 Kafka 扩展能力背后的核心概念。 假设我们的系统变得非常流行,因此每秒有数百万条日志消息。 所以现在 appLogs 主题所在的节点无法保存所有传入的数据。我们最初通过向我们的节点添加更多存储来解决这个问题,即垂直缩放。 但众所周知,垂直扩展有其局限性,一旦达到该阈值,我们就需要水平扩展,这意味着我们需要添加更多节点并在节点之间拆分数据。 当我们将一个主题的数据拆分为多个流时,我们将所有这些较小的流称为该主题的“分区”。

此图描述了分区的概念,其中单个主题有 4 个分区,并且所有分区都包含一组不同的数据。 您在此处看到的块是该分区中的不同消息。 假设主题是一个数组,现在由于内存限制,我们将单个数组拆分为 4 个不同的较小数组。 当我们向主题写入新消息时,会选择相关分区,然后将该消息添加到数组的末尾。

消息的偏移量是该消息的数组索引。 此图中块上的数字表示偏移量,第一个块位于第 0 个偏移量,最后一个块将位于第 (n-1) 个偏移量。 系统的性能还取决于您设置分区的方式,我们将在本文后面进行研究。 (请注意,在 Kafka 上,它不是一个实际的数组,而是一个符号数组)

生产者

生产者是向 Kafka 主题发布消息的 Kafka 客户端。 此外,生产者的核心职责之一是决定将消息发送到哪个分区。 根据各种配置和参数,生产者决定目标分区,让我们更深入地了解一下。

  1. 未指定key => 当消息中未指定key时,生产者将随机决定分区并尝试平衡所有分区上的消息总数。
  2. 指定key => 当消息指定了一个键时,生产者使用一致性哈希将键映射到一个分区。 如果您不知道什么是一致性哈希,请不要担心,简而言之,它是一种哈希机制,始终为相同的key生成相同的哈希,并且它最大限度地减少了重新哈希场景或将节点添加到集群中的key的重新分配 。 因此,假设在我们的日志系统中,我们使用源节点 ID 作为键,那么同一节点的日志将始终进入同一分区。 这与 Kafka 中消息的顺序保证非常相关,我们很快就会看到如何。
  3. 指定分区 => 您也可以对目标分区进行硬编码。
  4. 自定义分区逻辑 => 我们可以根据分区编写一些规则。

消费者

到目前为止,我们已经生成了消息,我们使用 Kafka 消费者读取这些消息。 消费者以有序的方式从分区中读取消息。 因此,如果将 1、2、3、4 插入到主题中,消费者将以相同的顺序阅读它。 由于每条消息都有一个偏移量,每次消费者读取消息时,它都会将偏移量值存储到 Kafka 或 Zookeeper 中,表示这是消费者读取的最后一条消息。 因此,万一消费者节点出现故障,它可以返回并从上次读取的位置恢复。 此外,如果在任何时间点消费者需要回到过去并阅读旧消息,它可以通过重置偏移位置来实现。

消费者组

消费者组是一起工作以从主题中读取消息的消费者的集合。 这里有一些非常有趣的概念,让我们来看看它们。

  1. Fan out exchange => 单个主题可以被多个消费者组订阅。 假设您正在构建 OTP 服务。
  1. 现在您需要发送文本和电子邮件 OTP。 所以你的OTP服务可以把OTP放到Kafka里面,然后SMS Service consumer group和Email Service consumer group都可以收到消息,然后可以发送SMS和email出去。
  2. 顺序保证=> 既然知道了topic是可以分区的,多个consumers可以从同一个topic消费,那么大家可能会问,consumer端消息的顺序怎么维护。 好问题。 一个分区不能被同一消费者组中的多个消费者读取。 这仅由消费者组启用,组中只有一个消费者可以从单个分区读取数据。

所以你的生产者产生了 6 条消息。 每条消息都是一个键值对,键“A”的值为“1”,“C”的值为“1”,“B”的值为“1”,“C”的值为“2”…… .. “B”值为“2”。 (请注意,我所说的键是指我们之前讨论的消息键,而不是 JSON 或 Map 键)。 我们的主题有 3 个分区,由于具有相同键的一致性哈希消息总是进入同一个分区,所以所有以“A”为键的消息将被分成一组,B 和 C 也是如此。现在每个分区都只有一个消费者,他们只能按顺序获取消息。 所以消费者将在 A2 之前收到 A1,在 B2 之前收到 B1,因此顺序得以维持。 回到我们的日志系统示例,键是源节点 ID,然后节点 1 的所有日志将始终进入同一个分区。 由于消息总是发送到同一个分区,我们将保持消息的顺序。

如果同一个分区在同一个组中有多个消费者,这将是不可能的。 如果您在不同组中的不同消费者中读取相同的分区,那么对于每个消费者组,消息最终也会按顺序排列。

所以对于 3 个分区,你最多可以有 3 个消费者,如果你有 4 个消费者,一个消费者将闲置。 但是对于 3 个分区,您可以有 2 个消费者,然后一个消费者将从一个分区读取,一个消费者将从两个分区读取。 如果在这种情况下一个消费者宕机,最后一个幸存的消费者将最终从所有三个分区读取数据,当新的消费者被添加回来时,分区将再次在消费者之间拆分,这称为重新平衡。

Broker

broker是单个 Kafka 服务器。 broker从生产者那里接收消息,为它们分配偏移量,然后将它们提交到分区日志,这基本上是将数据写入磁盘,这赋予了 Kafka 持久性。

集群

Kafka 集群是一组协同工作以提供可伸缩性、可用性和容错性的broker节点。 集群中的一个节点作为控制器工作,它基本上将分区分配给broker,监控broker是否无法执行某些管理工作。

在集群中,分区根据主题的复制因子被复制到多个broker上以具有故障转移能力。 我的意思是,对于一个复制因子为 3 的主题,该主题的每个分区将存在于 3 个不同的broker上。 当一个分区被复制到 3 个 broker 上时,其中一个 broker 将充当该分区的领导者,其余两个将成为追随者。 数据总是写在 leader broker 上,然后复制到 followers。 这样我们就不会丢失数据,也不会丢失集群的可用性,如果 leader 宕机,另一个 leader 会被选举出来。

让我们看一个实际的例子。 我在本地运行一个 5 节点的 Kafka 集群,我运行这个命令

代码语言:javascript复制
bin/kafka-topics.sh --bootstrap-server 192.168.49.2:30092 --topic applog --partitions 5 --replication-factor 3 --create

集群将

  1. 创建主题
  2. 创建该主题的 5 个分区
  3. 并将所有 5 个主题的数据复制到总共 3 个节点中

让我们以分区 0 为例,该分区的领导节点是节点 2。该分区的数据在节点 2,5 和 1 上复制。所以一个分区在 3 个节点上复制,并且对所有 5 个分区重复此行为。 而且如果你看到的话,每个分区的所有领导节点都是不同的。 因此,为了正确利用节点,Kafka controller broker 将分区均匀分布在所有节点上。 您还可以观察到复制也是均匀分布的,没有节点过载。 所有这些都是在 Zookeeper或者KRaft(3.3.1生产可用) 的帮助下由控制器 Broker 完成的。

由于您现在已经理解了集群,您可以看到我们可以对一个主题进行更多分区,并且对于每个分区,我们可以添加一个专用的消费者节点,这样我们就可以水平扩展。

高级点的东西

除此之外,还有一些你应该知道的稍微高级的东西,只是简单介绍一下。

Producer

你可以以3种方式发送数据到kafka

  1. 发送即忘记
  2. 同步发送
  3. 异步发送

他们都有自己的性能与一致性陷阱。

您也可以在生产者上配置确认特征。

  • ACK 0:不要等待确认 |FASTEST
  • ACK 1:考虑在 leader broker 收到消息时发送确认 |FASTER
  • ACK All:当所有副本收到消息时考虑发送确认|FAST

在发送给broker之前,您可以在生产者上压缩和以批的方式处理消息。

它提供高吞吐量并降低磁盘使用率,但会提高 CPU 使用率。

Avro 序列化器/反序列化器

如果您使用 Avro 作为序列化器/反序列化器而不是普通的 JSON,您将必须预先声明您的模式,这会提供更好的性能并节省存储空间。

Consumer

循环轮询

Kafka 消费者不断从broker轮询数据,反之亦然。

可以配置分区分配策略

Range:Consumer获取连续的partitions

循环法:循环往分区写数据

Sticky:重新平衡保持大部分分配不变同时创建最小影响

Cooperative sticky:Sticky分区方法,但允许合作再平衡

批大小

我们可以配置每次轮询调用返回多少条记录和多少数据。

提交偏移量

在读取消息时,我们可以更新消费者的偏移量位置,这称为提交偏移量。 可以启用自动提交,或者应用程序可以显式提交偏移量。 这可以同步和异步完成。

End

Kafka 是一款很棒的软件,具有大量功能,可用于各种用例。 Kafka 非常适合现代分布式系统,因为它是按分布式进行设计的。 它最初创建于 LinkedIn,目前由 Confluent 维护。 Uber、Netflix、Activision、Spotify、Slack、Pinterest、Coursera 等顶级科技公司都在使用它。

参考文档

https://medium.com/inspiredbrilliance/kafka-basics-and-core-concepts-5fd7a68c3193

5 1 投票

文章评分

本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://cloud.tencent.com/developer/article/2183262

0 人点赞