Apache Kafka 中的发布-订阅消息传递

2025 年 5 月 15 日 | 阅读 11 分钟

发布-订阅(pub-sub)消息传递是一种消息模式,其中发送方(发布者)发送消息,而无需了解接收方(订阅者),订阅者接收消息,而无需知道来源。Apache Kafka 作为一个分布式流处理平台,实现了发布-订阅模型,以实现可伸缩、容错和分布式通信。

Kafka 中,生产者将消息发送到特定的主题,消费者从这些主题中读取消息。Kafka 解耦了生产者和消费者,从而实现了一个高度可伸缩的系统。

Kafka 的发布-订阅模型围绕三个主要组件展开

  1. 生产者:向 Kafka 主题发送(发布)消息的应用程序。
  2. 消费者:从 Kafka 主题读取(订阅)消息的应用程序。
  3. 主题:主题就像一个通道,消息被发送到这里供其他人阅读。它是 Kafka 中表示记录日志的主要抽象。

Kafka 中发布-订阅消息传递的关键概念

  1. 生产者和消费者的解耦
    Kafka 的发布-订阅模式支持异步通信。生产者和消费者独立运行,这意味着生产者可以在不等待消费者准备就绪的情况下发送消息。同样,消费者可以按照自己的节奏订阅和读取消息。
  2. 主题
    在 Kafka 中,消息被发送到“主题”,主题充当提要名称,多个消费者可以订阅该提要。Kafka 主题被分区以实现并行性和可伸缩性。
  3. 分割
    Kafka 将主题分成多个分区。每个分区都是按顺序排列的消息列表,这有助于 Kafka 轻松扩展。生产者将消息发送到特定分区,消费者从这些分区读取消息。

消费者组

Kafka 允许消费者成为消费者组的一部分。这确保了主题分区的消息由组中的一个消费者读取,有助于均匀分配工作。

偏移量管理

Kafka 存储分区中每条消息的偏移量(位置)。消费者可以提交其偏移量,从而允许他们从上次离开的位置恢复消费,使 Kafka 成为发布-订阅消息传递的可靠平台。

Kafka 发布-订阅架构

在 Kafka 中,发布-订阅架构围绕生产者、代理、消费者、消费者组主题分区展开。这种设置确保数据以易于扩展且即使出现问题也能继续工作的方式从生产者发送到消费者。

让我们深入了解每个组件并在必要时提供示例程序。

1. 生产者

  • 生产者负责将消息发布到 Kafka 主题。在发布-订阅模型中,生产者发送数据时无需知道订阅者(消费者)是谁。
  • 生产者可以根据键(以确保消息发送到特定分区)或使用轮询逻辑均匀分发消息来决定将消息发送到哪个分区。

生产者示例程序

输出

Publish-Subscribe Messaging in Apache Kafka

说明

  • 此 Kafka 生产者将 5 条带有键值对的消息发送到主题 example-topic。键决定了消息存储在哪个分区中(基于 Kafka 的分区策略)。如果未提供键,Kafka 会使用轮询方法分发消息。

2. 代理

  • Kafka 代理管理消息的存储和检索。它们从生产者接收消息并将其存储在分区中。代理通过在多个代理之间复制消息来确保容错。
  • Kafka 集群中的每个代理都负责管理一个或多个主题分区。Kafka 的领导者-跟随者模型确保只有一个代理(领导者)处理给定分区的读/写操作,而其他代理复制领导者的数据。
  • 代理由 Kafka 本身管理,您通过 Kafka 客户端(生产者和消费者)与它们交互。您可以在 Kafka 的配置文件中定义集群中的代理数量,并启动多个代理实例以确保分发和容错。

3. 消费者

  • 消费者订阅主题以读取消息。一个消费者可以从多个主题或分区读取,多个消费者可以订阅同一个主题。
  • 消费者异步读取消息,允许它们独立处理数据。

消费者示例程序

输出

Publish-Subscribe Messaging in Apache Kafka

说明

  • 消费者订阅主题 example-topic 并实时消费消息。
  • 消费者可以指定其 group.id,这允许 Kafka 协调同一组中多个消费者之间的负载平衡(更多内容见下一节)。

4. 消费者组

  • 消费者组是消费者团队,它们协作从主题的不同部分读取数据。Kafka 确保组中只有一个消费者从每个部分读取消息,从而有助于分配任务。
  • 如果消费者数量多于分区数量,则一些消费者将无事可做。如果消费者数量少于分区数量,则一些消费者将负责多个分区。

组中多个消费者示例

您可以通过运行多个具有相同 group.id 的实例来稍微修改之前的消费者程序。Kafka 将自动为组中的消费者分配分区,确保来自不同分区的消息由不同的消费者处理。

5. 主题分区

  • Kafka 主题被分成称为“分区”的部分,以帮助处理更多数据并加快速度。每个分区都像一个有序的消息列表,不同的消费者(读取消息的程序)可以同时从不同的分区读取。
  • 分区允许数据并行处理,并且在每个分区内,消息保持有序。Kafka 将这些分区分布在多个代理(服务器)上,以确保系统即使在服务器故障时也能继续工作。

生产者中的分区示例

您可以通过明确指定分区或使用 Kafka 将哈希以确定分区的键来控制生产者的分区。

或者通过使用键让 Kafka 决定

消费者中检查分区

在消费时,您可以使用消费者中的 record.partition() 方法查看正在从哪个分区读取消息。

Kafka 发布-订阅消息传递中的消息顺序

在 Kafka 的发布-订阅消息传递中,消息顺序在确保消费者以一致且可预测的方式接收消息方面起着关键作用。Kafka 保证消息在分区内有序,但不保证主题所有分区的全局顺序。在此设置中,生产者将消息发送到主题,消费者订阅这些主题以读取消息。

消息的顺序会影响生产者(发送消息时)和消费者(接收消息时)。

让我们分解一下消息顺序在 Kafka 发布-订阅模型中是如何工作的。

1. Kafka 中的发布-订阅模型

在 Kafka 中,一个主题被分成分区,生产者和消费者都与这些分区交互。

  • 生产者将消息发送到主题,Kafka 确保具有相同键的消息始终发送到同一分区。
  • 消费者订阅主题并从分区读取消息。如果消费者属于一个组,Kafka 会将每个分区分配给组中的一个消费者,从而允许同时读取多个分区。

关键点

  • 分区:Kafka 将消息分布在分区中以实现可伸缩性和并行性。
  • 分区内排序:Kafka 保证单个分区内的消息按其生产顺序排列。
  • 无全局排序:Kafka 不保证跨分区的消息顺序,因为分区由不同的消费者或消费者组独立消费。

2. 生产者级别的消息顺序

生产者向 Kafka 发送消息时,它可以决定如何对消息进行分区。Kafka 的消息顺序在很大程度上取决于消息如何路由到分区。

关键方法

  • 基于键的分区:如果生产者为消息分配一个键,Kafka 会使用分区策略(通常是键的哈希值)将具有相同键的消息发送到同一分区。这确保所有具有相同键的消息保持有序。
    • 例如,如果消息与特定用户(例如 user1、user2)相关,并且键是用户 ID,则 user1 的所有操作都将路由到同一分区,确保它们按正确的顺序处理。
  • 轮询分区:如果未提供键,Kafka 可以以轮询方式将消息分布到分区中。在这种情况下,顺序只在每个分区内保留,但消息可以在分区之间混合。

生产者级别基于键的排序示例

在此示例中

  • user1 的两条消息都将路由到同一分区,从而保留其顺序。

3. 代理级别的消息顺序

Kafka 代理在维护分区级别的消息顺序方面起着关键作用。一旦生产者发送消息,代理就会将消息分配到正确的分区并将其附加到分区日志的末尾。

  • Kafka 确保消息按顺序写入每个分区的日志,保留从生产者接收的顺序。
  • 如果启用了复制,则分区的追随者会按相同的顺序复制领导者的消息,确保即使代理发生故障,顺序也保持一致。

示例

  • 生产者发送消息:M1、M2、M3,键为 user1。所有这些消息都路由到分区 1
  • Kafka 代理按 M1 -> M2 -> M3 的顺序将这些消息附加到分区日志。

4. 消费者级别的消息顺序

在发布-订阅模型中,消费者负责从 Kafka 分区读取消息。Kafka 确保分配给分区的单个消费者以生产者写入的相同顺序读取消息。

关键点

  • 消费者组:在消费者组中,每个分区只分配给一个消费者。这允许跨分区并行消费,但每个分区内的消息保持有序。
  • 分区级别排序:消费者组中的每个消费者都将按其生产顺序接收其分配分区中的消息。
  • 偏移量管理:Kafka 消费者使用偏移量跟踪其在分区日志中的位置。消费者当前的偏移量表示分区中接下来应该消费哪条消息。如果提供了键,则所有具有该键的消息都将发送到同一分区,确保它们保持偏移量顺序。

有序消费示例

在此示例中

  • 因为 Kafka 保证分区级别排序,所以相同键 (user1) 的消息将按其生产顺序消费。

5. Kafka 发布-订阅架构中的消息顺序如何工作?

总结 Kafka 发布-订阅模型不同组件之间的消息顺序处理方式

5.1. 生产者的角色

  • 生产者将消息发送到 Kafka,这些消息被路由到特定的分区。
  • 如果提供了键,则所有具有该键的消息都将发送到同一分区,确保它们按顺序交付。
  • 如果没有键,消息可能会随机分布到分区中,导致分区之间的无序交付。

5.2. 代理的角色

  • Kafka 代理以收到消息的精确顺序将消息存储在分区中。
  • 它将消息添加到分区末尾并通过跨不同代理复制数据来保持顺序。

5.3. 消费者的角色

  • 消费者按顺序从分区读取消息,保持分区内的顺序。
  • 在消费者组中,Kafka 确保一次只有一个消费者从一个分区读取,从而保留分区级别顺序。
  • 如果消费者发生故障,Kafka 会将分区重新分配给组中的另一个消费者,新消费者将从上次提交的偏移量继续读取。

6. 示例

这是一个完整的示例,演示了 Kafka 发布-订阅模型中的消息顺序

生产者程序(发送有序消息)

输出

Publish-Subscribe Messaging in Apache Kafka

消费者程序(按顺序消费消息)

输出

Publish-Subscribe Messaging in Apache Kafka

Kafka 发布-订阅消息传递中的高级概念

1. 消息保留

Kafka 根据可配置的时间或大小保留消息。以下是根据时间配置消息保留的示例

根据大小配置保留

2. 复制

复制对于 Kafka 的容错至关重要。您可以在创建主题时指定复制因子

3. 消费者偏移量管理

Kafka 自动将消费者偏移量存储在一个特殊主题 (__consumer_offsets) 中。您可以使用 Kafka Consumer API 手动提交偏移量来管理偏移量

4. 至少一次与最多一次语义

对于至少一次语义(默认行为)

对于最多一次语义

5. 压缩主题

为主题启用日志压缩

在此模式下,Kafka 仅保留每个键的最新值,丢弃旧记录。