当前位置: 首页 > news >正文

202535| Kafka架构与重要概念+幂等性+事务

好的!以下是关于 Kafka 架构 以及其 重要概念 的详细介绍,结合 Mermaid 图形表格,帮助你更好地理解各个概念的关系和作用。


Kafka 架构与重要概念

Kafka 是一个分布式消息系统,广泛应用于日志收集、流处理、事件驱动架构等场景。它采用高吞吐量、可扩展的架构,支持多个组件进行数据的发布、订阅、存储和消费。

一、Kafka 架构图(Mermaid 格式)

Topic 分区
发送消息
存储消息
发送消息
存储消息
存储消息
协调与管理
消费消息
消费消息
Partition 0
Leader: Kafka-1
Replica: Kafka-2, Kafka-3
Partition 1
Leader: Kafka-2
Replica: Kafka-1, Kafka-3
Partition 2
Leader: Kafka-3
Replica: Kafka-1, Kafka-2
Producer
Kafka Broker 1
ZooKeeper
Kafka Broker 2
Consumer Group

二、Kafka 重要概念详细解释

概念说明
BrokerKafka 服务器节点,负责存储和管理消息。每个 Broker 处理多个 Topic 和 Partition 的数据读写。
ZooKeeper分布式协调服务,Kafka 用它来管理集群的元数据,协调 Broker 状态,选举 Leader 等。
Producer消息的生产者,将数据发布到指定的 Topic 中。
Consumer消息的消费者,从 Kafka 中获取数据并进行处理。
Consumer Group由多个 Consumer 组成,Kafka 会确保每个分区在 Consumer Group 中只被一个消费者消费。
TopicKafka 中的主题,用于组织和分类消息。
Partition每个 Topic 被划分为多个分区,分区是 Kafka 存储消息的基本单位。
Replica分区的副本,确保数据的高可用性。每个分区可以有多个副本,其中一个为 Leader。
OffsetKafka 中每条消息在分区内的唯一标识,消费者通过 Offset 来追踪自己消费的进度。

三、Kafka 架构中的各个组件

1. Broker(Kafka 代理)

  • 定义:Kafka 中的 Broker 是负责存储消息并处理客户端请求的节点。每个 Broker 负责多个 Topic 和 Partition 的数据读写。
  • 角色:Kafka 集群由多个 Broker 组成,集群中的 Broker 节点共同工作,确保数据的存储、消费和高可用性。
  • 作用:Broker 接受来自 Producer 的消息,将其存储在本地磁盘中,并提供 Consumer 按需读取。

2. ZooKeeper(协调服务)

  • 定义:ZooKeeper 是一个分布式协调服务,用于管理 Kafka 集群的元数据和协调 Broker 的状态。Kafka 使用 ZooKeeper 来进行 Broker 的注册、Leader 选举等管理操作。
  • 作用:它帮助 Kafka 保持一致性、选举 Leader 和管理集群状态。ZooKeeper 集群中可以有多个节点,提供高可用性。

3. Producer(生产者)

  • 定义:Producer 是向 Kafka 集群发送消息的客户端。它将消息发送到指定的 Topic 中。
  • 作用:Producer 可以选择发送到特定的 Partition,也可以选择由 Kafka 自动分配 Partition。
  • 分区选择:Producer 可以通过指定一个 key 来确保某一类消息始终发送到同一个分区,或者由 Kafka 根据负载均衡策略自动选择。

4. Consumer(消费者)

  • 定义:Consumer 是从 Kafka 中读取消息并处理的客户端。它可以订阅一个或多个 Topic,读取分区中的消息。
  • 作用:Consumer 从 Kafka 中消费消息,通常会从消息的 Offset 开始读取。消费者通常会在自己的 Offset 位置继续消费。

5. Consumer Group(消费组)

  • 定义:Consumer Group 是由多个 Consumer 组成的一组消费者。每个 Consumer Group 内的消费者共同消费同一个 Topic 的消息,但每个分区的消息只有一个消费者消费。
  • 作用:通过消费组,Kafka 可以实现消息的并行消费。每个消费组都会维护自己的 Offset 独立于其他消费组。

6. Topic(主题)

  • 定义:Topic 是 Kafka 中的消息分类标签。Producer 将消息发送到特定的 Topic,Consumer 可以订阅一个或多个 Topic 来消费消息。
  • 作用:Topic 是 Kafka 消息的逻辑分组,可以帮助管理不同种类的消息流。

7. Partition(分区)

  • 定义:每个 Topic 会被划分成多个 Partition,Partition 是 Kafka 存储消息的最小单位。每个分区存储消息的顺序,并且每个 Partition 都有一个 Leader 和若干个 Follower 副本。
  • 作用:分区提供了水平扩展的能力,可以增加分区来处理更高的消息吞吐量和并发消费。

8. Replica(副本)

  • 定义:每个分区都有多个副本(Replica),其中一个副本是 Leader,负责处理所有的读写请求。其他副本是 Follower,负责同步数据。
  • 作用:副本保证了 Kafka 集群的数据高可用性和容错性。即使某个 Broker 节点失败,其他副本仍然可以保证数据不丢失。

9. Offset(偏移量)

  • 定义:Offset 是 Kafka 中每条消息在分区内的唯一标识。每个消费者在消费消息时都会记录自己的 Offset 位置。
  • 作用:Offset 使得 Kafka 的消息消费具有高可控性。消费者可以从特定的 Offset 开始消费消息,也可以重新从头消费历史消息。

Kafka生产者幂等性

Kafka 生产者的幂等性功能是为了保证消息的 一次性写入。即使在网络超时、生产者重试等情况下,消息依然能够保证 只被写入一次。为了实现这一目标,Kafka 利用一系列机制来控制消息的重复发送,并对每条消息进行唯一标识。

Kafka 生产者幂等性核心概念

  1. Producer ID (PID): 每个 Kafka 生产者实例都会在启动时获取一个唯一的 Producer ID。这是 Kafka 用来区分不同生产者的标识符,确保每个生产者发送的消息在 Kafka 集群中都有唯一标识。
  2. Sequence Number (序列号): 每个生产者发送的消息都有一个递增的序列号,Sequence Number 是 Kafka 用来判定消息是否重复的关键参数。序列号的递增可以确保即使是同一个生产者发送多条消息,Kafka 也能区分它们。
  3. Message Key & Partition: 消息的 Key 用来决定消息将发送到哪个分区,确保同一个 Key 的消息总是发送到同一个分区。分区内的消息顺序对于幂等性没有影响,但消息的重复性检查依赖于 Producer ID 和 Sequence Number。

生产者幂等性工作流程

为了解释 Kafka 是如何确保消息不被重复写入,我们可以将其工作过程分解为几个步骤:

  1. 生产者初始化
    • 每个生产者在启动时会向 Kafka 集群申请一个唯一的 Producer ID (PID),并且会从 Kafka 中获得一个初始的 Sequence Number
    • 生产者为每条发送的消息附上递增的序列号。
  2. 消息发送
    • 生产者向 Kafka 发送消息时,消息携带两个关键字段:Producer IDSequence Number。这些字段帮助 Kafka 区分不同生产者发送的消息,以及同一生产者发送的不同消息。
  3. 消息接收与存储
    • Kafka Broker 在接收到消息后,会先检查 Producer IDSequence Number。如果该消息的 Sequence Number 对应的消息已经存在,说明这是一个 重复消息,则 Kafka 会 忽略 该消息,不进行存储。
    • 如果消息是新的,Kafka 会将其存储,并将该消息的 Producer IDSequence Number 存储在元数据中。
  4. 消息重试
    • 在网络延迟或其他故障的情况下,生产者可能会重试发送相同的消息。由于生产者会附带相同的 Producer IDSequence Number,Kafka Broker 会识别到这是同一条消息,并 忽略 重试请求,确保消息只被写入一次。
  5. 消息确认
    • 在消息成功写入 Kafka 后,Broker 会将写入成功的确认返回给生产者。若发生故障或超时,生产者会继续重试,直到成功或者达到重试次数的上限。

Kafka 生产者幂等性详细流程图

为了让你更直观地理解这一过程,下面是一个更详细的图解,展示了生产者发送消息、重试以及如何避免重复消息写入的流程:

生产者 Kafka Broker ZooKeeper 消费者 生产者启动时,分配一个唯一的 PID 发送消息(消息 1) PID: 123 Sequence: 0 存储消息 1 的元数据 传递消息 1 网络延迟或故障,生产者重试发送相同消息 发送消息(消息 1) PID: 123 Sequence: 0 检查消息 1 是否已存在 消息已存在,重试请求忽略 不发送重复消息 发送消息(消息 2) PID: 123 Sequence: 1 存储消息 2 的元数据 传递消息 2 每条消息的 PID 和 Sequence Number 保证唯一性 生产者的 Sequence Number 在重试时会保持一致,确保幂等性 生产者 Kafka Broker ZooKeeper 消费者

工作原理解读

1. 生产者启动时

当生产者启动时,Kafka 为该生产者分配一个 Producer ID(如 123),并且给该生产者分配一个递增的 Sequence Number(从 0 开始)。每个消息都携带这些信息,确保 Kafka 能识别该生产者的每一条消息。

2. 生产者发送消息(消息 1)

生产者发送 消息 1 到 Kafka 集群,消息的内容包括:Producer ID: 123 和 Sequence Number: 0。Kafka 会根据这个信息将消息存储并传递给消费者。

3. 网络故障与重试

由于网络延迟或其他原因,生产者可能会重试发送相同的消息。此时,生产者再次发送 消息 1(Producer ID: 123, Sequence: 0)。Kafka 在收到这条消息时,会检查消息的 Producer IDSequence Number,发现这条消息已经存在,因此会 忽略 重复的消息。

4. 发送新的消息(消息 2)

当生产者发送 消息 2 时,Sequence Number 增加为 1,Kafka 会识别为新消息,并将其存储和传递给消费者。


Kafka 幂等性实现的关键因素

  1. Producer ID (PID)
    • 每个生产者在 Kafka 中都有一个唯一的 Producer ID,它用来标识消息的来源。即使网络重试,Kafka 也能根据 Producer ID 来区分不同的生产者。
  2. Sequence Number
    • 每个生产者发送的消息都有一个递增的序列号。这个序列号使 Kafka 能够区分同一生产者发送的不同消息,确保消息的顺序性。
  3. 去重机制
    • Kafka 使用 Producer IDSequence Number 来判断消息是否重复。如果收到相同 Producer IDSequence Number 的消息,Kafka 会认为这是一条重复消息,进而忽略它。
  4. 跨分区的一致性
    • Kafka 的幂等性机制是 跨分区的,即使消息被发送到多个分区,只要生产者的 Producer IDSequence Number 相同,Kafka 就会确保消息不重复写入。

生产者幂等性机制的优缺点

优点
  1. 保证消息准确性:即使发生网络重试、故障等问题,生产者也能保证消息 只写一次,避免了数据的重复和不一致。
  2. 提升容错能力:在发生故障或超时的情况下,生产者能够安全重试,并且 Kafka 会确保不会重复写入消息,增强了系统的容错性。
  3. 避免消费者重复消费:幂等性机制确保了消费者不会收到重复的消息,避免了重复消费和数据错误。
缺点
  1. 性能开销:启用幂等性会增加一定的性能开销,尤其在高吞吐量的场景下,Kafka 需要进行更多的检查和存储操作来确保消息唯一性。
  2. 对多生产者的支持有限:幂等性机制仅对单一生产者实例有效,不同生产者间无法共享幂等性状态。

Kafka 生产者幂等性配置示例

以下是一个典型的 Kafka 生产者配置,启用了幂等性功能:

java复制编辑
Properties properties = new Properties();
properties.put("bootstrap.servers", "localhost:9092");
properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");// 启用幂等性
properties.put("acks", "all");  // 等待所有副本确认
properties.put("retries", Integer.MAX_VALUE);  // 设置最大重试次数为最大值
properties.put("max.in.flight.requests.per.connection", 1);  // 防止并发请求导致乱序
properties.put("enable.idempotence", "true");  // 启用幂等性KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
配置详解
  1. acks=all:等待所有副本确认后才返回确认,提供了最佳的消息可靠性。
  2. retries=Integer.MAX_VALUE:允许生产者无限次重试,直到成功。通过幂等性机制,Kafka 确保即使消息重试,也不会重复写入。
  3. max.in.flight.requests.per.connection=1:为了确保消息的顺序性,生产者一次只允许发送一个未确认的消息。
  4. enable.idempotence=true:启用幂等性,确保消息只写一次,即使发生重试,消息也不会重复。

KafKa事务

Kafka 事务简介

Kafka 的事务是一个强大的特性,它允许用户将多个消息的发送操作封装在一个 原子操作 中。通过事务,生产者可以确保多条消息的发送要么全部成功,要么全部失败。Kafka 的事务能够保证数据一致性,特别是在分布式环境下,避免了部分消息写入而其他消息丢失的问题。

Kafka 事务不仅仅用于生产者,也为消费者提供了 精确一次消费(Exactly Once Semantics, EOS)的能力。事务在 Kafka 中的应用解决了消息重复消费和漏消费的难题,提升了消息流的可靠性。


Kafka 事务的核心特点

  1. 原子性(Atomicity): Kafka 事务保证一组消息的发送要么全部成功,要么全部失败。若消息在事务内的某些操作失败,那么整个事务会被回滚,确保消息的原子性。
  2. 可靠性(Durability): 一旦事务提交,Kafka 会保证消息持久化,并且可以恢复事务内的消息。
  3. 一致性(Consistency): Kafka 确保事务内的消息要么全都提交,要么全都回滚,避免了数据不一致的情况。
  4. 隔离性(Isolation): Kafka 确保事务内的消息在事务提交之前对消费者是不可见的。即消费者只能看到已经提交的消息,未提交的事务消息对消费者是不可见的。

Kafka 事务的实现

Kafka 使用以下两种类型的标记来管理事务:

  • 事务开始:生产者发出开始事务的信号,所有后续发送的消息都属于这个事务。
  • 事务提交:生产者发出提交事务的信号,Kafka 将事务中的所有消息持久化,确保消息可供消费者读取。
  • 事务中止(回滚):如果生产者遇到错误并决定放弃事务,可以发出中止事务的信号,所有事务内的消息都不会被提交。

Kafka 会在事务日志中记录每个事务的状态。事务状态包括提交、回滚或未决(进行中)。


Kafka 事务的关键配置

  1. acks
    • 设置为 all,确保所有副本都确认消息,以提高消息可靠性和容错性。
  2. transactional.id
    • 这是 Kafka 生产者的一个关键配置,标识一个生产者实例的事务标识符。每个事务性生产者都需要设置这个唯一的标识符,以便 Kafka 能追踪事务状态。
  3. retries
    • 在事务中,重试机制非常重要,设置 retries 可以确保生产者在事务中的消息如果失败,可以重试。
  4. transaction.timeout.ms
    • 这个配置用于设置事务的超时时间,默认值是 60000 毫秒。若一个事务未在指定时间内提交或回滚,Kafka 会认为事务超时并自动中止事务。
  5. enable.idempotence
    • 在启用事务的同时,还需要启用幂等性,这样可以确保即使在网络中断或生产者重试的情况下,也不会重复发送相同的消息。

Kafka 事务的生产者使用流程

  1. 开启事务: 在生产者代码中,需要使用 beginTransaction() 方法显式地开始一个事务。
  2. 发送消息: 在事务中发送消息时,所有发送的消息都会被标记为事务的一部分,直到事务被提交或回滚。
  3. 提交事务: 通过 commitTransaction() 方法提交事务,Kafka 会将事务中的所有消息持久化。
  4. 回滚事务: 如果在事务过程中发生了错误,生产者可以使用 abortTransaction() 方法回滚事务,所有未提交的消息都不会被持久化。

事务的生产者代码示例

以下是一个使用 Kafka 事务的 Java 代码示例,演示如何开启事务、发送消息并提交事务。

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");
props.put("retries", Integer.MAX_VALUE);
props.put("transactional.id", "my-transaction-id");// 创建 KafkaProducer 实例
KafkaProducer<String, String> producer = new KafkaProducer<>(props);try {// 开始事务producer.beginTransaction();// 发送消息producer.send(new ProducerRecord<>("my-topic", "key1", "value1"));producer.send(new ProducerRecord<>("my-topic", "key2", "value2"));// 提交事务producer.commitTransaction();
} catch (ProducerFencedException | OutOfMemoryError | KafkaException e) {// 在发生异常时回滚事务producer.abortTransaction();
} finally {producer.close();
}

代码解释:

  1. 初始化生产者:配置 bootstrap.serversacks 等基本参数,并设置 transactional.id 来启用事务。
  2. 开始事务:通过 beginTransaction() 方法启动一个事务。
  3. 发送消息:消息会被添加到当前事务中,直到事务提交或回滚。
  4. 提交事务commitTransaction() 方法将事务中的所有消息持久化到 Kafka 集群中。
  5. 异常处理和回滚:如果发生异常(如网络中断、写入失败等),调用 abortTransaction() 方法回滚事务,确保事务内的消息不被写入。

Kafka 事务的消费者

Kafka 的事务不仅对生产者有效,还影响消费者的行为。启用事务后,消费者只能看到已经提交的消息,这意味着未提交的事务对消费者是不可见的。这保证了 精确一次消费(Exactly Once Semantics,EOS),确保消费者不会消费到重复或不完整的数据。

消费者的事务性读取:
  • 如果消费者消费到一个尚未提交的消息,它会等待直到该消息所在的事务提交。
  • 如果事务被回滚,消费者不会读取到该事务中的消息。
启用精确一次消费:

为了启用精确一次的消费,消费者需要设置 isolation.level 配置项,通常设置为 read_committed,这意味着消费者只会读取已提交的消息。

Properties consumerProps = new Properties();
consumerProps.put("bootstrap.servers", "localhost:9092");
consumerProps.put("group.id", "my-consumer-group");
consumerProps.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
consumerProps.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
consumerProps.put("isolation.level", "read_committed");KafkaConsumer<String, String> consumer = new KafkaConsumer<>(consumerProps);
consumer.subscribe(Collections.singletonList("my-topic"));while (true) {ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));for (ConsumerRecord<String, String> record : records) {System.out.println("Consumed: " + record.value());}
}

总结:Kafka 事务的优势

  1. 消息的原子性:保证一组消息的发送操作要么完全成功,要么完全失败。避免了部分消息写入成功而其他消息丢失的情况。
  2. 精确一次语义(EOS):通过生产者事务和消费者的事务性读取,Kafka 提供了精确一次的消息传递语义,确保数据的一致性。
  3. 高可靠性:在分布式环境下,事务能够确保即使在故障和重试的情况下,数据不会重复或者丢失,保证了消息传递的可靠性。
  4. 简化消费者逻辑:启用事务后,消费者无需额外的逻辑去处理重复数据,Kafka 会自动保证消费者只处理已提交的消息。

通过 Kafka 事务,用户可以构建更加稳定和一致的数据流系统,尤其适用于金融、订单等要求高数据一致性的场景。

相关文章:

  • FreeSWITCH 简单图形化界面42 - 使用mod_vad模块进行语音检测
  • 可以抛弃postman啦, API测试工具Bruno实用教程(二):进阶篇
  • 高斯过程回归(GPR)原理的通俗解释
  • 从 SpringBoot 到微服务架构:Java 后端开发的高效转型之路
  • 5.2 参数管理
  • vue3的响应式设计原理
  • Tengine:高性能Web服务器的原理与应用实践优雅草卓伊凡
  • 通俗的桥接模式
  • 如何安装不同版本的ESP-IDF,并配置Vscode插件,以及在Vscode中切换版本
  • Linux:进程间通信---消息队列信号量
  • Linux 信号终篇(总结)
  • HTTP/3展望、我应该迁移到HTTP/2吗
  • LeetCode 270:在二叉搜索树中寻找最接近的值(Swift 实战解析)
  • 从父类到子类:C++ 继承的奇妙旅程(2)
  • LinkedList源码解析
  • 嵌入式硬件篇---麦克纳姆轮(简单运动实现)
  • 【金仓数据库征文】国产数据库KingbaseES安装与使用详解
  • 深度解析 MySQL 与 Spring Boot 长耗时进程:从故障现象到根治方案(含 Tomcat 重启必要性分析)
  • Java与Go语言对比教程
  • LeetCode --- 448 周赛
  • 红场阅兵即将开始!中国人民解放军仪仗队亮相
  • 市自规局公告收回新校区建设用地,宿迁学院:需变更建设主体
  • 中信银行:拟出资100亿元全资设立信银金融资产投资有限公司
  • 马克思主义理论研究教学名师系列访谈|曾瑞明:想通了才可能认准,认准了才能做好
  • 牛市早报|央行宣布降准降息,公募基金改革最新方案落地
  • 媒体起底“速成洋文凭”灰产链,专家:我们要给学历“祛魅”