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

Kafka底层结构

1. Kafka 架构总览

Kafka 是一个分布式消息队列,采用**发布-订阅(Pub-Sub)**模式,核心组件包括:

  • Producer(生产者): 负责向 Kafka 发送消息。
  • Broker(Kafka 服务器): 负责存储和管理消息。
  • Topic(主题): 消息的分类单元。
  • Partition(分区): Topic 的物理分片,提高吞吐量。
  • Consumer(消费者): 订阅并消费消息。
  • Consumer Group(消费者组): 消费者的逻辑分组,支持并行消费。
  • Zookeeper: 负责 Kafka 集群的元数据管理、Leader 选举等。

2. 底层存储结构

Kafka 采用顺序写入日志文件的方式存储数据,底层存储采用**Segment(日志分段)+ Index(索引)**的方式管理数据。

2.1 日志存储

  • 每个 Partition 对应一个日志目录,目录结构如下:

/kafka-logs/
  ├── topic-1/
  │   ├── 0/  # 分区0
  │   │   ├── 00000000000000000000.log  # 日志文件
  │   │   ├── 00000000000000000000.index  # 索引文件
  │   │   ├── 00000000000000000000.timeindex  # 时间索引文件
  │   │   ├── leader-epoch-checkpoint  # 领导者任期记录
  • 日志分段(Segment)

    • Kafka 不会将所有消息存入一个文件,而是拆分成多个段文件(Segment),每个 Segment 都是一个固定大小(默认1GB)的日志文件。
    • 新消息总是追加到当前活跃段(Active Segment),当文件达到一定大小后,Kafka 会新建一个段文件
  • 索引机制

    • 索引文件(.index): 记录消息在日志文件中的偏移量和物理位置。
    • 时间索引(.timeindex): 通过时间戳查找最近的消息,提高查询效率。

2.2 日志清理(Log Retention & Compaction)

Kafka 提供两种清理策略:

  • 日志保留(Retention): Kafka 按照**时间(log.retention.hours)或大小(log.retention.bytes)**删除旧数据,默认存储 7 天。
  • 日志压缩(Log Compaction): 仅保留最新的 Key-Value 记录,适用于 幂等性数据存储 场景。

3. 生产者消息投递

生产者(Producer)负责将消息发送到 Kafka,Kafka 采用以下机制保证消息可靠性:

  • 分区策略(Partitioning)

    • 轮询(Round-Robin): 生产者将消息平均分配到不同的分区。
    • 按 Key 选择(Keyed Partitioning): 生产者根据 Key 计算 Hash 值,映射到固定分区,保证相同 Key 的消息进入同一个分区。
    • 自定义策略(Custom Partitioning): 用户可以自定义分区规则。
  • 消息确认机制(Acknowledgment)

    • acks=0:不等待确认,可能丢失数据。
    • acks=1:只需 Leader 记录消息,可能丢失数据(Leader 崩溃)。
    • acks=all:所有副本都写入后才确认,保证最高可靠性。
  • 批量发送(Batching)

    • Kafka 生产者默认支持批量发送(Batch),提高吞吐量。
    • 通过参数 batch.size 控制批量大小。
  • 压缩(Compression)

    • Kafka 支持 GZIP、Snappy、LZ4、Zstd 压缩方式,减少带宽占用。

4. 消费者消费机制

消费者从 Kafka 拉取数据,采用 Consumer Group(消费者组) 机制保证数据分发:

  • 每个分区只能被一个组内的消费者消费,保证同一条消息不会被组内多个消费者重复消费
  • 不同的 Consumer Group 可以并行消费同一 Topic,提高并发能力。

4.1 消息拉取方式

Kafka 采用Pull(拉取)模式,而非传统的Push(推送)模式

  • Push 模式:生产者主动推送数据,可能导致消费者过载。
  • Pull 模式:消费者自主决定拉取频率,避免过载问题,提高吞吐量。

4.2 消费者偏移量(Offset)管理

Kafka 使用消费者位移(Offset) 记录消费进度:

  • 自动提交(enable.auto.commit=true): 消费者定期提交偏移量,可能丢失数据。
  • 手动提交: 通过 commitSync()commitAsync() 提交偏移量,保证消费的可靠性。

4.3 Rebalance 机制

当消费者加入/退出消费者组,Kafka 会进行重新分配分区(Rebalance)

  • Rebalance 触发条件
    • 新消费者加入
    • 消费者故障
    • 分区数变化

5. 分区副本(Replication)机制

Kafka 采用副本机制(Replication) 保证数据高可用:

  • 每个分区都有多个副本(Replica),其中:

    • Leader 副本 负责读写数据。
    • Follower 副本 仅做同步,供故障转移使用。
  • ISR(In-Sync Replicas)同步机制

    • Kafka 维护同步副本集合(ISR),存储最新的同步副本。
    • 仅 ISR 内的副本能当选 Leader,保证数据一致性。
  • 副本选举(Leader Election)

    • 当 Leader 崩溃,Kafka 会自动选举新的 Leader,保证服务可用。

6. 高吞吐设计

Kafka 采用多种优化策略,提高吞吐能力:

  • 零拷贝(Zero-Copy)
    • 采用 sendfile 系统调用,避免数据在用户态和内核态之间拷贝,提高性能。
  • 顺序写入
    • Kafka 采用顺序写入磁盘,减少随机 IO,提升写入速度。
  • 批量处理
    • 生产者批量发送消息,减少网络开销,提高吞吐量。

7. Zookeeper 在 Kafka 中的作用

Kafka 依赖 Zookeeper 进行集群管理,主要包括:

  • 存储元数据
    • 记录 Topic、分区、副本等信息。
  • 选举 Kafka Controller
    • 控制分区的 Leader 选举,维护集群状态。
  • 消费者 Rebalance
    • 协调 Consumer Group,触发 Rebalance。

一致性设计

1. 生产者一致性保证

生产者一致性主要涉及数据是否成功写入 Kafka,并且不会丢失或重复,Kafka 提供以下机制来保证生产者一致性:

1.1 ACK 确认机制

Kafka 生产者在发送消息时,依赖 acks 参数来确认数据是否成功写入 Kafka:

  • acks=0:不等待确认,最快,但可能会丢失数据(不一致)。
  • acks=1:只等待Leader 副本确认,存在 Leader 崩溃导致数据丢失的风险。
  • acks=all(或 acks=-1):等待所有 ISR 副本确认,确保数据不会丢失,但写入延迟较高。

最佳实践:

  • 对于高一致性要求,建议使用 acks=all
  • 可结合 min.insync.replicas 配置,确保至少有 N 个副本 成功写入后才确认。

1.2 生产者重试机制

Kafka 生产者可能因网络问题、Broker 宕机等原因发送失败。Kafka 通过重试机制提高数据一致性:

  • retries=N:指定重试次数。
  • retry.backoff.ms:两次重试之间的时间间隔。

⚠️ 注意:

  • retries > 0,但 max.in.flight.requests.per.connection > 1,可能导致消息乱序
  • 解决方案:
    • 保证消息顺序:设置 max.in.flight.requests.per.connection=1

最佳实践:

  • 对于幂等性保证,需配合 enable.idempotence=true(见下一节)。
  • retries 设为较大值(如 retries=5),避免短期故障导致数据丢失。

1.3 幂等性(Idempotency)

Kafka 生产者默认情况下可能会在重试过程中导致重复消息,可以启用幂等性保证数据一致性:

  • enable.idempotence=true:Kafka 生产者端启用幂等性,确保同一条消息只写入一次,即使发生重试。

Kafka 通过Producer ID(PID)+ Sequence Number 组合,确保相同 Producer 发送的消息不会被重复写入。

最佳实践:

  • 强烈建议在高一致性场景下启用幂等性 enable.idempotence=true
  • acks=all + enable.idempotence=true 可实现**"Exactly Once"(精准一次)** 语义。

1.4 事务保证(Exactly-Once)

Kafka 生产者支持事务(Transactional),确保跨分区或跨批次的消息要么全部成功,要么全部失败

启用事务时:

  1. 生产者调用 initTransactions() 初始化事务。
  2. 生产者调用 beginTransaction() 开始事务。
  3. 生产者发送消息。
  4. 生产者调用 commitTransaction() 提交事务,或 abortTransaction() 回滚事务。

最佳实践:

  • 事务适用于涉及多个 Topic 或多个分区的消息处理场景,如金融系统、订单系统
  • 事务模式下,必须启用 acks=allenable.idempotence=true

2. 消费者一致性保证

Kafka 消费者一致性主要涉及:

  1. 消息不丢失(At-Least-Once)
  2. 消息不重复(At-Most-Once)
  3. 精准一次消费(Exactly-Once)

Kafka 通过消费偏移量(Offset)管理事务消费等机制实现不同级别的一致性保证。


2.1 消费者偏移量(Offset)管理

Kafka 采用**偏移量(Offset)**来记录消费者消费的进度,Kafka 提供三种消费语义:

语义解释偏移提交时机可能的问题
At-Most-Once(最多一次)可能丢失消息,但不重复在消费前提交失败后消息丢失
At-Least-Once(至少一次)确保不丢失,但可能重复在消费后提交失败可能导致重复消费
Exactly-Once(精准一次)消费恰好一次事务消费 + 幂等性需要事务支持

最佳实践:

  • 默认 Kafka 消费是 At-Least-Once,即消费后提交偏移量,可能导致重复消费。
  • 避免重复消费:
    • 可结合 幂等性 机制(如数据库 UPSERT 操作)。
    • 使用事务消费(见下一节)。

2.2 事务消费(Exactly-Once)

Kafka 事务消费(Exactly-Once Processing,EoS)保证消费者端的精准一次处理:

  • read_process_commit 原子性
    • 事务保证了读取、处理和提交偏移量要么全部完成,要么全部失败。
  • Kafka Streams API
    • Kafka Streams 提供内置Exactly-Once 语义,自动处理事务提交。

最佳实践:

  • 使用 Kafka Streams 进行 EoS 消费(推荐)。
  • 如果用普通消费者:
    • enable.auto.commit=false,手动提交偏移量。
    • 结合 commitSync() 和事务 commitTransaction() 共同确保一致性。

2.3 Rebalance 影响一致性

当 Consumer Group 发生**Rebalance(重新分配分区)**时,可能导致:

  • 重复消费:如果 Rebalance 发生在偏移量提交前,可能导致部分消息重复消费。
  • 消息丢失:如果 Rebalance 发生后,某些未提交偏移量的消息未处理完。

最佳实践:

  • 使用 StickyAssignorCooperativeStickyAssignor,减少 Rebalance 影响。
  • 手动提交偏移量(commitSync),确保处理完数据后才提交。

总结

机制生产者一致性消费者一致性
ACK 机制acks=all 确保数据写入成功-
重试机制retries>0,避免瞬时失败-
幂等性enable.idempotence=true,防止重复写入-
事务beginTransaction() + commitTransaction()read_process_commit 事务消费
偏移量管理-enable.auto.commit=false + commitSync()
Rebalance 处理-使用 StickyAssignor 方案减少影响

最终推荐方案:

  • 生产者acks=all + enable.idempotence=true + transactional.id
  • 消费者enable.auto.commit=false + commitSync() + 事务消费

这些优化方案可以保证 Kafka "Exactly-Once"(精准一次) 语义,确保生产者和消费者数据一致性。


http://www.kler.cn/a/570696.html

相关文章:

  • 【算法系列】基数排序
  • 【CSS—前端快速入门】CSS 选择器
  • 内网渗透信息收集linuxkali扫描ip段,收集脚本(web安全)
  • FlashMLA(DeepSeek开源周,第一个框架):含源码分析
  • DDD该怎么去落地实现(4)多对多关系
  • Docker安装Postgres_16数据库
  • cordova app webpack升级为vite
  • B3DM转换成OBJ
  • 图论-腐烂的橘子
  • 汽车轮胎损伤缺陷分割数据集labelme格式1957张3类别
  • 【Elasticsearch】时间序列数据流(Time Series Data Stream,TSDS)
  • 【原创】Ubuntu 24自动分区后的根目录扩展
  • 配置Spring Boot API接口超时时间(五种)
  • C++学习之C++初识、C++对C语言增强、对C语言扩展
  • 基于vue3 + ts 封装一个自定义的message组件
  • 基于机器学习的智能谣言检测系统
  • java jar包内的jar包如何打补丁
  • 2022 年 12 月青少年软编等考 C 语言五级真题解析
  • 第6篇:面向对象编程重构系统
  • Spring MVC 返回数据