Kafka 从入门到精通 --- 完整学习笔记
服务器环境 :华为云 ecs-7c2c x 4 台 | Ubuntu 24.04 | 2vCPU/4GiB
Kafka 版本 :4.3.0 | Scala 2.13 | KRaft 模式(无 ZooKeeper)
集群架构 :3 Controller + 1 Broker | 内网互联 192.168.0.x
集群 UUID :1S9ggrMYQaCHBqfZy8hhOg
实战日期:2026-06-01
目录
- [第一章:Kafka 基础入门](#第一章:Kafka 基础入门)
- [第二章:Kafka 安装与配置](#第二章:Kafka 安装与配置)
- [第三章:Kafka 核心 API 详解](#第三章:Kafka 核心 API 详解)
- [第四章:Kafka 核心机制深入](#第四章:Kafka 核心机制深入)
- [第五章:Kafka 生产者详解](#第五章:Kafka 生产者详解)
- [第六章:Kafka 消费者详解](#第六章:Kafka 消费者详解)
- [第七章:Kafka 集群管理](#第七章:Kafka 集群管理)
- [第八章:Kafka 安全机制](#第八章:Kafka 安全机制)
- [第九章:Kafka Streams 与 KSQL](#第九章:Kafka Streams 与 KSQL)
- [第十章:Kafka Connect 数据集成](#第十章:Kafka Connect 数据集成)
- [第十一章:Kafka 性能优化](#第十一章:Kafka 性能优化)
- [第十二章:Kafka 运维与故障排查](#第十二章:Kafka 运维与故障排查)
- [第十三章:Kafka 实战项目案例](#第十三章:Kafka 实战项目案例)
- [第十四章:Kafka 新特性与未来](#第十四章:Kafka 新特性与未来)
- [第十五章:Kafka 面试与进阶](#第十五章:Kafka 面试与进阶)
- 附录
第一章:Kafka 基础入门
1.1 消息队列与 Kafka 概述
1.1.1 消息队列概念与作用
消息队列(Message Queue) 是一种异步通信中间件,允许应用程序通过发送和接收消息来进行通信,而不需要彼此同时在线。
┌──────────────────────────────────────────────────────────────────┐
│ 消息队列核心价值 │
│ │
│ [Producer A] ──┐ ┌── [Consumer X] │
│ │ │ │
│ [Producer B] ──┼──► [Message Queue] ──┼── [Consumer Y] │
│ │ │ │
│ [Producer C] ──┘ └── [Consumer Z] │
│ │
│ 解耦:生产者和消费者独立演进 │
│ 削峰:应对流量突增,保护下游系统 │
│ 异步:非阻塞通信,提升系统响应速度 │
│ 可靠:消息持久化,保证不丢失 │
│ 顺序:支持消息顺序性保证 │
└──────────────────────────────────────────────────────────────────┘
为什么需要消息队列:
| 问题 | 无消息队列 | 有消息队列 |
|---|---|---|
| 系统耦合 | 服务直接调用,一方故障全链路阻塞 | 服务通过消息通信,独立部署 |
| 流量冲击 | 秒杀场景 10000 QPS 直接打崩数据库 | 消息队列缓冲,后端按能力消费 |
| 数据丢失 | 服务故障,请求数据丢失 | 消息持久化到磁盘,故障恢复后可消费 |
| 扩展性 | 消费端扩容需要修改上游 | 消费者组支持动态增减实例 |
| 协议适配 | 异构系统直连需要统一协议 | 消息队列屏蔽协议差异 |
1.1.2 消息队列模式
点对点模式(Point-to-Point / Queue):
[Producer] ──► [Queue] ──► [Consumer A]
消息被一个消费者消费后即删除
- 一条消息只能被一个消费者消费
- 消费者消费后消息从队列删除
- 多个消费者可共享消费负载(竞争消费)
- 典型代表:RabbitMQ(Work Queue)
发布订阅模式(Publish-Subscribe / Topic):
┌── [Subscriber A]
[Publisher] ──► [Topic] ──┼── [Subscriber B]
└── [Subscriber C]
一条消息可以被多个订阅者消费
- 一条消息可以被多个消费者(订阅者)消费
- 消费者需要提前订阅 Topic
- 消息被所有订阅者消费后才删除
- Kafka 本质上是发布订阅模式的分布式实现
1.1.3 Kafka 定义与特点
Apache Kafka 是一个分布式流处理平台,具有以下核心能力:
Kafka 三大定位:
1. 消息队列 --- 高吞吐、低延迟的消息传递系统
发布 & 订阅消息流,类似消息队列或企业消息系统
2. 存储系统 --- 持久化、容错的分布式日志存储
以容错、持久的方式存储消息流
3. 流处理 --- 实时处理消息流
在消息流产生时即对其进行处理
Kafka 核心特点:
| 特性 | 说明 | 实战数据 |
|---|---|---|
| 高吞吐 | 单 Broker 可达数十万 msg/s | 本次 ~13K msg/s(2vCPU/4GiB 受限) |
| 低延迟 | P50 延迟 < 10ms(本地网络) | 本次 P50 = 56ms(跨公网 ECS) |
| 持久化 | 消息写入磁盘,零拷贝读取 | 日志段(Log Segment)持久化 |
| 水平扩展 | Broker 动态增减,分区重新分配 | 4 Broker 集群,在线扩容 |
| 容错 | 副本机制,ISR 自动故障转移 | RF=3,min.insync.replicas=2 |
| 顺序保证 | 分区内消息严格有序 | Key 路由验证:同一 Key 固定分区 |
| 多客户端 | Java/Python/Go/C++/Rust 等 | Java 官方 + kafka-python 验证通过 |
1.1.4 Kafka 发展历程与版本演进
2010 --- LinkedIn 开发 Kafka,用于活动流数据管道
2011 --- Apache 孵化器项目,0.7 版本发布
2012 --- Apache 顶级项目,0.8 版本(引入副本机制)
2014 --- 0.8.2 版本(日志压缩)
2015 --- 0.9.0 版本(安全特性 SSL/SASL)
2016 --- 0.10.0 版本(Kafka Streams)
2017 --- 0.11.0 版本(Exactly-Once 语义、事务)
2018 --- 1.0.0 / 2.0.0(性能优化、JMX 监控增强)
2019 --- 2.3.0(增量消费者组再均衡)
2020 --- 2.6.0(KRaft 早期预览)
2021 --- 2.8.0(KRaft 可用于生产)
2022 --- 3.3.0(KRaft 生产就绪)
2023 --- 3.6.0(Tiered Storage 早期预览)
2024 --- 3.7.0 / 3.8.0(KRaft ZooKeeper 弃用)
2025 --- 3.9.0(KRaft 模式优化)
2026 --- **4.3.0(完全 KRaft,无 ZK 代码)← 当前版本**
版本选择建议:
| 版本线 | ZK 依赖 | KRaft | 推荐场景 |
|---|---|---|---|
| < 2.8 | 必须 | 不可用 | 存量老系统 |
| 2.8 - 3.2 | 可选 | 预览 | 测试环境尝鲜 |
| 3.3 - 3.9 | 可选 | 生产就绪 | 过渡期,可双模式 |
| 4.x | 已移除 | 唯一模式 | 新项目首选 |
1.1.5 Kafka 应用场景
┌─────────────────────────────────────────────────────────────────┐
│ Kafka 典型应用场景 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 日志收集 (Log Aggregation) │
│ App Logs → Filebeat → Kafka → Logstash → Elasticsearch │
│ │
│ 2. 流处理 (Stream Processing) │
│ Events → Kafka → Kafka Streams / Flink → 实时大盘 │
│ │
│ 3. 事件溯源 (Event Sourcing) │
│ 所有状态变更作为事件流存入 Kafka,可回溯重建任意时刻状态 │
│ │
│ 4. 消息系统 (Messaging) │
│ 微服务间异步通信,解耦服务依赖 │
│ │
│ 5. 指标收集 (Metrics) │
│ 系统指标 → Kafka → Prometheus / InfluxDB │
│ │
│ 6. CDC 数据同步 (Change Data Capture) │
│ MySQL Binlog → Debezium → Kafka → 数据仓库/Hadoop │
│ │
└─────────────────────────────────────────────────────────────────┘
1.2 Kafka 与竞品对比
1.2.1 Kafka vs RabbitMQ
| 维度 | Kafka | RabbitMQ |
|---|---|---|
| 设计理念 | 分布式日志 (append-only log) | 消息代理 (AMQP 协议) |
| 吞吐量 | 极高(百万级/秒) | 中等(万级/秒) |
| 消息持久化 | 默认持久化到磁盘 | 可选持久化(内存/磁盘) |
| 消费者模型 | Pull 拉取模式 | Push 推送模式 |
| 消息回溯 | 支持(保留期内任意 offset 回放) | 不支持 |
| 分区 | 核心概念,分区内有序 | 无分区(Exchange + Queue) |
| 路由灵活性 | 简单(Topic → Partition) | 复杂(Exchange + Routing Key + Binding) |
| 协议 | 自定义二进制协议 | AMQP 0-9-1 |
| 事务支持 | 支持(Exactly-Once) | 部分支持 |
| 适用场景 | 大数据管道、流处理、事件驱动 | 传统消息队列、RPC 调用、任务队列 |
1.2.2 Kafka vs RocketMQ
| 维度 | Kafka | RocketMQ |
|---|---|---|
| 开发语言 | Java/Scala | Java |
| 社区 | Apache 顶级项目,全球社区 | 阿里开源,国内生态强 |
| 事务消息 | 支持(幂等 + 事务) | 原生支持(半消息机制) |
| 延迟消息 | 需自行实现 | 原生支持 18 个延迟级别 |
| 消息过滤 | 客户端侧过滤 | Broker 侧 SQL 过滤 |
| 重试机制 | 需自行实现 | 内置消费重试 + 死信队列 |
| 顺序消息 | 分区内有序 | 分区内有序(支持全局有序) |
| 适用场景 | 大数据/流处理场景 | 电商/金融业务消息 |
1.2.3 Kafka vs Pulsar
| 维度 | Kafka | Pulsar |
|---|---|---|
| 架构 | Broker 一体(计算+存储绑定) | 计算存储分离(Broker + BookKeeper) |
| 多租户 | 有限(通过 Topic 前缀) | 原生多租户(Tenant/Namespace) |
| Geo-Replication | MirrorMaker 2 | 原生跨地域复制 |
| 消息确认 | Offset 提交 | 单条消息确认(Ack) |
| 队列模式 | 通过 Consumer Group 模拟 | 原生支持 Queue + Stream |
| 分层存储 | 4.x Tiered Storage | 原生 Tiered Storage |
| 运维复杂度 | 较低 | 较高(BookKeeper + ZooKeeper) |
1.2.4 Kafka vs ActiveMQ
| 维度 | Kafka | ActiveMQ |
|---|---|---|
| 吞吐量 | 极高 | 中等偏低 |
| 协议支持 | 自定义 | 多协议(AMQP/MQTT/STOMP/OpenWire) |
| 持久化 | 基于日志段 | 基于 KahaDB/JDBC |
| 集群 | 原生分布式 | Broker 网络(Network of Brokers) |
| 现代性 | 活跃开发,4.x 持续迭代 | Classic 已停维,Artemis 活跃 |
1.2.5 选型建议
选 Kafka 如果:
✓ 需要高吞吐(百万 msg/s 级别)
✓ 需要消息回溯能力(Event Sourcing)
✓ 需要流处理(Kafka Streams / KSQL)
✓ 已有大数据生态(Hadoop/Spark/Flink)
✓ 团队熟悉 Java/Scala 生态
选 RocketMQ 如果:
✓ 需要事务消息(分布式事务场景)
✓ 需要定时/延迟消息
✓ 国内主流互联网公司环境
✓ 需要更丰富的消息模型
选 RabbitMQ 如果:
✓ 需要灵活的路由规则
✓ 需要低延迟(微秒级 RPC)
✓ 团队熟悉 AMQP 协议
✓ 消息量不高(万级/秒以下)
选 Pulsar 如果:
✓ 需要计算存储分离
✓ 需要原生多租户
✓ 需要队列 + 流双模式
1.3 Kafka 核心概念
1.3.1 概念全景图
┌─────────────────────────────────────────────────────────────────────┐
│ Kafka 核心概念全景 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Producer │ │ Consumer │ │
│ │ 生产者 │ │ 消费者 │ │
│ │ (push data) │ │ (pull data) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ send(message, topic, [key]) │ poll() │
│ ▼ │ │
│ ┌───────────────────────────────────────────────────▼──────────┐ │
│ │ Kafka Cluster │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Topic: "orders" Partition Count: 4 │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │Partition0│ │Partition1│ │Partition2│ │Partition3│ │ │ │
│ │ │ │ 0 1 2 3..│ │ 0 1 2 3..│ │ 0 1 2 3..│ │ 0 1 2 3..│ │ │ │
│ │ │ │ (Leader) │ │ (Leader) │ │ (Leader) │ │ (Leader) │ │ │ │
│ │ │ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ Broker 4 │ │ │ │
│ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Broker 1 ─ Broker 2 ─ Broker 3 ─ Broker 4 │ │
│ │ (Controller) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Consumer Group "order-processor" │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Consumer A│ │Consumer B│ │Consumer C│ │
│ │P0, P1 │ │P2 │ │P3 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ 每个分区只被组内一个消费者消费 │
└─────────────────────────────────────────────────────────────────────┘
1.3.2 核心概念详解
Topic(主题)
Topic 是消息的逻辑分类,类似于数据库的"表"概念。
生产者将消息发送到特定 Topic,消费者从 Topic 订阅消息。
实战示例:
Topic: test-basic --- 基础功能测试
Topic: test-compact --- 压缩策略测试
Topic: test-perf --- 性能压测
Topic: __consumer_offsets --- 消费者偏移量内部主题
Partition(分区)
Topic 在物理上被分割为多个 Partition,每个 Partition 是一个有序、不可变的消息序列。
┌──────────────────────────────────────────────┐
│ Partition 0: [msg0] [msg1] [msg2] [msg3]... │
│ Partition 1: [msg0] [msg1] [msg2]... │
│ Partition 2: [msg0] [msg1] [msg2]... │
│ Partition 3: [msg0] [msg1] [msg2] [msg3]... │
└──────────────────────────────────────────────┘
分区的作用:
1. 水平扩展 --- 单个 Topic 可跨多台 Broker 存储
2. 并行消费 --- 多个消费者可并行消费不同分区
3. 顺序保证 --- 分区内消息严格有序(按 offset)
实战验证 --- Key 分区路由:
# Python Producer 发送 10 条消息,按 user-{0,1,2} 作为 Key
Sent: key=user-0 → partition=3, offset=0
Sent: key=user-1 → partition=0, offset=10
Sent: key=user-2 → partition=0, offset=11
Sent: key=user-0 → partition=3, offset=1 ← 同一 Key 回同一分区!
Sent: key=user-1 → partition=0, offset=12
Sent: key=user-2 → partition=0, offset=13
Sent: key=user-0 → partition=3, offset=2
Sent: key=user-1 → partition=0, offset=14
Sent: key=user-2 → partition=0, offset=15
Sent: key=user-0 → partition=3, offset=3
结论:相同 Key 的消息一定进入同一个 Partition,保证该 Key 的消息顺序性。
分区算法:partition = hash(key) % num_partitions
Broker(代理)
Broker 是 Kafka 服务器节点,负责消息存储、请求处理、副本管理。
实战集群 (4 Brokers):
Broker 1 (kafka-01) --- node.id=1, Controller + Broker
Broker 2 (kafka-02) --- node.id=2, Controller + Broker
Broker 3 (kafka-03) --- node.id=3, Controller + Broker
Broker 4 (kafka-04) --- node.id=4, Broker Only (Observer)
Producer(生产者)
Producer 负责将消息发送到指定的 Topic。
Producer 发送流程:
1. 序列化 Key 和 Value
2. 选择目标分区(Key Hash / Round-Robin / 自定义)
3. 消息进入 RecordAccumulator 缓冲区
4. Sender 线程批量发送到 Broker
5. 等待 Broker 确认(根据 acks 配置)
关键参数:
- acks=0:不等待确认,最快但可能丢失
- acks=1:等待 Leader 确认
- acks=all:等待所有 ISR 确认,最安全
Consumer(消费者)
Consumer 从 Broker 拉取(Pull)消息进行处理。
关键行为:
- 消费者主动拉取(非 Push),可自行控制消费速度
- 消费者属于某个 Consumer Group
- 通过 Offset 记录消费位置
- 支持从任意 Offset 开始消费(earliest/latest/指定)
Consumer Group(消费者组)
Consumer Group 是 Kafka 实现消息广播和单播的核心机制:
- 一条消息可以被多个 Consumer Group 消费(广播)
- 在一个 Group 内,一个 Partition 只能被一个 Consumer 消费(单播)
┌─────────────────────────────────────────────────────────┐
│ Group A (实时处理): Consumer A1(P0,P1), A2(P2), A3(P3) │
│ Group B (离线分析): Consumer B1(P0,P1,P2,P3) │
│ Group C (监控告警): Consumer C1(P0,P1,P2,P3) │
│ │
│ 同一条消息被 3 个 Group 独立消费,互不影响 │
└─────────────────────────────────────────────────────────┘
Offset(偏移量)
Offset 是消息在 Partition 中的唯一递增编号,用于定位消息位置。
Partition 0: [msg(offset=0)] [msg(offset=1)] [msg(offset=2)] ...
↑
消费者当前消费位置
Offset 管理方式:
- 自动提交:enable.auto.commit=true(默认,5秒提交一次)
- 手动同步提交:consumer.commitSync()
- 手动异步提交:consumer.commitAsync()
Replica(副本)
每个 Partition 有多个 Replica(副本):
┌──────────────────────────────────────────┐
│ Partition 0: RF=3 │
│ │
│ Broker 3: [Leader] --- 处理读写请求 │
│ Broker 4: [Follower] --- 从 Leader 同步 │
│ Broker 1: [Follower] --- 从 Leader 同步 │
│ │
│ ISR (In-Sync Replicas): [3, 4, 1] │
│ HW (High Watermark): 消费者可见最高偏移 │
│ LEO (Log End Offset): 副本最新写入位置 │
└──────────────────────────────────────────┘
实战验证:
Topic: test-basic Partition: 0 Leader: 3 Replicas: 3,4,1 Isr: 3,4,1
Topic: test-basic Partition: 1 Leader: 4 Replicas: 4,1,2 Isr: 4,1,2
Topic: test-basic Partition: 2 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
Topic: test-basic Partition: 3 Leader: 2 Replicas: 2,3,4 Isr: 2,3,4
所有分区 ISR 完整,Leader 均匀分布在 4 个 Broker。✓
1.4 Kafka 架构设计
1.4.1 系统架构图
┌──────────────────────────────────────────────────────────────────────┐
│ Kafka 4.3.0 KRaft 架构 │
│ │
│ ┌─────────────────── Controller Quorum ─────────────────────────┐ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ │
│ │ │ ID: 1 │ │ ID: 2 │ │ ID: 3 │ │ │
│ │ │ Controller │◄──► Controller │◄──► Controller │ │ │
│ │ │ + │ │ + │ │ + │ │ │
│ │ │ Broker │ │ Broker │ │ Broker │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │ │
│ └─────────┼──────────────────┼──────────────────┼────────────────┘ │
│ │ │ │ │
│ │ ┌────────┼──────────────────┼──────┐ │
│ │ │ │ │ │ │
│ │ │ ┌────▼──────────────────▼──┐ │ │
│ │ │ │ Broker 4 │ │ │
│ │ │ │ ID: 4 │ │ │
│ │ │ │ Broker Only │ │ │
│ │ │ │ (Observer, 不参与选举) │ │ │
│ │ │ └───────────────────────────┘ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Metadata Layer │ │
│ │ - Topic 元数据(分区、副本分配) │ │
│ │ - Broker 注册信息 │ │
│ │ - Partition Leader 选举 │ │
│ │ - 基于 Raft 共识协议 (替代 ZooKeeper) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ /opt/kafka/data/ │ │
│ │ ├── test-basic-0/ (.log, .index, .timeindex) │ │
│ │ ├── test-basic-1/ │ │
│ │ ├── test-basic-2/ │ │
│ │ ├── test-basic-3/ │ │
│ │ └── __consumer_offsets-*/ │ │
│ └───────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
1.4.2 数据流架构
Kafka 数据流
┌──────────┐ ┌──────────────────────┐ ┌──────────┐
│ Producer │──1──►│ Kafka Cluster │──3──►│ Consumer │
│ │ │ │ │ │
│ 序列化 │ │ ┌────────────────┐ │ │ 反序列化 │
│ 分区选择 │ │ │ Network Layer │ │ │ 拉取消息 │
│ 批量发送 │ │ └───────┬────────┘ │ │ 处理消息 │
│ 压缩 │ │ │ │ │ 提交Offset│
└──────────┘ │ ┌───────▼────────┐ │ └──────────┘
│ │ API Layer │ │
2.写入请求 │ │ (KafkaApis) │ │ 4.拉取请求
│ └───────┬────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Replica Manager│ │
│ │ (副本同步管理) │ │
│ └───────┬────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Log Manager │ │
│ │ (磁盘持久化) │ │
│ └────────────────┘ │
└──────────────────────┘
1.4.3 集群架构设计
我们的实战集群 (4节点 KRaft):
┌──────────────────────────────────────────────────────────────┐
│ Controller Quorum (3节点, 多数派 = 2) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ kafka-01 │ │ kafka-02 │ │ kafka-03 │ │
│ │ 192.168.0.54 │ │ 192.168.0.228 │ │ 192.168.0.89 │ │
│ │ node.id=1 │ │ node.id=2 │ │ node.id=3 │ │
│ │ Active Leader │ │ Follower │ │ Follower │ │
│ │ Controller ✓ │ │ Controller ✓ │ │ Controller ✓│ │
│ │ Broker ✓ │ │ Broker ✓ │ │ Broker ✓ │ │
│ └────────┬────────┘ └────────┬────────┘ └──────┬───────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────┘ │
│ │ │
│ ┌─────────────────▼──────────┐ │
│ │ kafka-04 │ │
│ │ 192.168.0.128 │ │
│ │ node.id=4 │ │
│ │ Broker Only │ │
│ │ (Observer) │ │
│ └────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Quorum 状态:
ClusterId: 1S9ggrMYQaCHBqfZy8hhOg
LeaderId: 1 ← kafka-01 是 Active Controller
LeaderEpoch: 1
HighWatermark: 192
MaxFollowerLag: 0 ← 所有 Follower 完全同步
CurrentVoters: [1, 2, 3]
CurrentObservers: [4] ← kafka-04 不参与 Controller 投票
1.4.4 ZooKeeper 的作用(Kafka 2.x 之前)
ZooKeeper 在 Kafka 2.x 中的职责(已在新版本中移除):
┌─────────────────────────────────────────────────┐
│ ZooKeeper Ensemble │
│ │
│ 1. Controller 选举 │
│ /controller → {"brokerid": 1} │
│ │
│ 2. Broker 注册与发现 │
│ /brokers/ids/[0..N] → broker 信息 │
│ │
│ 3. Topic 配置管理 │
│ /brokers/topics/[topic_name] → 分区副本分配 │
│ │
│ 4. Partition Leader 选举 │
│ /brokers/topics/[topic]/partitions/[p]/state │
│ │
│ 5. Consumer Group 协调 (旧版) │
│ /consumers/[group]/offsets/[topic]/[partition] │
│ │
│ 6. ACL 权限存储 │
│ /kafka-acl/ │
└─────────────────────────────────────────────────┘
痛点(为什么抛弃 ZK):
✗ 运维复杂 --- 需要独立维护 ZooKeeper 集群
✗ 性能瓶颈 --- 元数据变更需写入 ZK,限制分区创建速度
✗ 一致性模型 --- ZK 和 Kafka 两个一致性系统协调困难
✗ 学习成本 --- 团队需要掌握两套系统
1.4.5 KRaft 模式(Kafka 3.x+,4.x 唯一模式)
KRaft (Kafka Raft) 是 Kafka 自管理的共识协议,替代 ZK。
核心概念:
┌─────────────────────────────────────────────────────┐
│ KRaft Metadata Quorum │
│ │
│ 基于 Raft 协议:Leader + Follower │
│ │
│ ┌──────────────┐ │
│ │ Quorum Leader │ ← Active Controller │
│ │ 接收所有元数据变更 │ │
│ │ 通过 Raft 复制到 │ │
│ │ Follower 节点 │ │
│ └──────┬───────┘ │
│ │ Raft Replication │
│ ┌────┼────┐ │
│ ▼ ▼ ▼ │
│ ┌────┐┌────┐┌────┐ │
│ │ F1 ││ F2 ││ F3 │ ← 需多数派确认 (N/2+1) │
│ └────┘└────┘└────┘ │
│ │
│ Metadata Topic: @metadata │
│ - 单一分区内部 Topic,存储所有集群元数据 │
│ - Leader Epoch 每次选举递增 │
│ - 支持快照 (Snapshot) 压缩 │
└─────────────────────────────────────────────────────┘
KRaft 优势:
✓ 架构简化 --- 无需维护 ZooKeeper 集群
✓ 性能提升 --- 元数据操作更快(无 ZK 写延迟)
✓ 运维简化 --- 单一系统,配置更少
✓ 扩展性 --- 支持更多分区(百万级→千万级)
✓ 启动速度 --- 无 ZK 连接等待,启动更快
实战配置:
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@192.168.0.54:9093,2@192.168.0.228:9093,3@192.168.0.89:9093
controller.listener.names=CONTROLLER
第二章:Kafka 安装与配置
2.1 环境准备
2.1.1 系统要求
| 组件 | 最低要求 | 推荐配置 | 我们的实战配置 |
|---|---|---|---|
| Java | JDK 17+ | JDK 21 | OpenJDK 21.0.11 |
| CPU | 2 核 | 4 核+ | 2 vCPU (ECS 基础型) |
| 内存 | 2 GB (heap 1G) | 8 GB+ (heap 6G) | 4 GB (heap 1G) |
| 磁盘 | 10 GB | 100 GB+ SSD | 40 GB 云盘 |
| 网络 | 1 Gbps | 10 Gbps | 华为云内网 |
| 文件描述符 | 100000 | 100000+ | 默认 (1024) |
| 操作系统 | Linux 3.x+ | Ubuntu 24.04 | Ubuntu 24.04 LTS |
2.1.2 网络配置要求
Kafka 4.x KRaft 网络端口:
┌──────────────────────────────────────────────────┐
│ 端口 │ 协议 │ 用途 │
├───────────┼─────────────┼─────────────────────────┤
│ 9092 │ PLAINTEXT │ Broker 对外服务 │
│ 9093 │ PLAINTEXT │ Controller 内部通信 │
│ 9094 │ SSL │ SSL 加密外部访问 (可选) │
│ 9095 │ SASL_SSL │ SASL+SSL 认证访问 (可选) │
└──────────────────────────────────────────────────┘
实战配置(内网 + 公网):
# 内网:Controller 通信,Broker 间数据同步
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
# 公网:Client 访问地址
advertised.listeners=PLAINTEXT://<公网IP>:9092
# Broker 间通信使用 PLAINTEXT listener
inter.broker.listener.name=PLAINTEXT
# Controller 通信使用 CONTROLLER listener
controller.listener.names=CONTROLLER
2.1.3 操作系统优化
bash
# 1. 文件描述符限制
ulimit -n 100000
# 持久化: /etc/security/limits.conf
# root soft nofile 100000
# root hard nofile 100000
# 2. 虚拟内存 (避免 OOM Killer)
sysctl -w vm.swappiness=1
# 3. 网络参数优化
sysctl -w net.core.rmem_default=1048576
sysctl -w net.core.wmem_default=1048576
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
# 4. 磁盘挂载选项 (如使用独立数据盘)
# mount -o noatime /dev/vdb1 /opt/kafka/data
2.2 Linux 环境安装
2.2.1 下载与安装 Kafka 4.3.0
bash
# 1. 安装 Java 21
sudo apt-get update
sudo apt-get install -y fontconfig openjdk-21-jre-headless
java -version
# openjdk version "21.0.11" 2026-04-21
# 2. 下载 Kafka (国内推荐阿里云镜像)
cd /opt
wget https://mirrors.aliyun.com/apache/kafka/4.3.0/kafka_2.13-4.3.0.tgz -O kafka.tgz
tar xzf kafka.tgz
mv kafka_2.13-4.3.0 kafka
rm kafka.tgz
# 3. 验证安装
ls /opt/kafka/bin/
# 共 44 个脚本文件
2.2.2 配置文件详解(server.properties)
完整配置及参数详解:
properties
# ===== KRaft 模式核心配置 =====
# process.roles --- 节点角色
# 可选值: broker, controller, broker,controller
# broker: 仅存储数据,处理客户端请求
# controller: 参与元数据仲裁(Raft Quorum)
# broker,controller: 同时承担两种角色(推荐,简化部署)
process.roles=broker,controller
# node.id --- Broker 唯一标识
# 每个 Broker 必须有不同的 ID,范围 0 ~ N
# 对应 controller.quorum.voters 中的 ID
node.id=1
# controller.quorum.voters --- Controller 仲裁节点列表
# 格式: {id}@{host}:{port},{id}@{host}:{port},...
# 必须列出所有 Controller 节点,数量应为奇数(3 或 5)
# 多数派 = N/2 + 1,3 节点可容忍 1 台故障
controller.quorum.voters=1@192.168.0.54:9093,2@192.168.0.228:9093,3@192.168.0.89:9093
# ===== 网络监听配置 =====
# listeners --- Broker 监听地址列表
# 格式: {协议}://{主机}:{端口}
# 0.0.0.0 表示绑定所有网络接口
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
# advertised.listeners --- 对外公布的访问地址
# 客户端通过此地址连接 Broker
# 必须使用客户端可访问的 IP/域名
# 如果 Broker 在 NAT/云环境,此处应为公网 IP
advertised.listeners=PLAINTEXT://119.3.218.94:9092
# inter.broker.listener.name --- Broker 间通信使用的 listener
# 对应 listeners 中的协议名(不是端口)
inter.broker.listener.name=PLAINTEXT
# controller.listener.names --- Controller 通信使用的 listener 列表
# 逗号分隔的协议名列表
controller.listener.names=CONTROLLER
# listener.security.protocol.map --- 协议名到安全协议的映射
# 格式: {协议名}:{安全协议},{协议名}:{安全协议},...
# 安全协议: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
# ===== 日志存储配置 =====
# log.dirs --- 数据存储目录
# 可配置多个目录(逗号分隔),Kafka 会将分区均匀分布
# 推荐使用独立磁盘/SSD
log.dirs=/opt/kafka/data
# num.partitions --- 新建 Topic 默认分区数
# 生产环境建议根据吞吐需求设置,通常 6~12
num.partitions=8
# default.replication.factor --- 默认副本因子
# 必须 ≤ Broker 数量,生产环境建议 3
default.replication.factor=3
# min.insync.replicas --- 最小同步副本数
# 配合 acks=all 使用,保证数据可靠性
# 通常设置为 replication.factor - 1
min.insync.replicas=2
# ===== 日志保留策略 =====
# log.retention.hours --- 消息保留时间(小时)
# 超过此时间的消息将被删除(delete 策略)或压缩(compact 策略)
# 默认 168 小时 = 7 天
log.retention.hours=168
# log.segment.bytes --- 单个日志段文件最大大小
# 到达此大小后,创建新的日志段
# 默认 1 GB = 1073741824
log.segment.bytes=1073741824
# log.retention.check.interval.ms --- 日志清理检查间隔
# 默认 300000 ms = 5 分钟
log.retention.check.interval.ms=300000
# ===== 网络线程配置 =====
# num.network.threads --- 网络线程数
# 处理网络请求的线程数,生产环境建议 CPU 核数
num.network.threads=3
# num.io.threads --- IO 线程数
# 处理磁盘 IO 的线程数,建议 CPU 核数 * 2
num.io.threads=8
# socket.send.buffer.bytes --- Socket 发送缓冲区大小
socket.send.buffer.bytes=102400
# socket.receive.buffer.bytes --- Socket 接收缓冲区大小
socket.receive.buffer.bytes=102400
# socket.request.max.bytes --- Socket 请求最大字节数
# 默认 100 MB = 104857600
socket.request.max.bytes=104857600
# ===== 内部 Topic 配置 =====
# offsets.topic.replication.factor --- __consumer_offsets 副本因子
# 建议与 default.replication.factor 一致
offsets.topic.replication.factor=3
# transaction.state.log.replication.factor --- 事务日志副本因子
transaction.state.log.replication.factor=3
# transaction.state.log.min.isr --- 事务日志最小 ISR
transaction.state.log.min.isr=2
# ===== 消费者组配置 =====
# group.initial.rebalance.delay.ms --- 初始重平衡延迟
# 设为 0 可加快首次消费启动
group.initial.rebalance.delay.ms=0
# ===== 压缩配置 =====
# compression.type --- 消息压缩算法
# producer: 保留生产者设置的压缩格式(推荐)
# 可选:none, gzip, snappy, lz4, zstd
compression.type=producer
2.2.3 KRaft 存储格式化
bash
# 1. 生成集群唯一 ID(仅在一个节点执行)
/opt/kafka/bin/kafka-storage.sh random-uuid
# 输出: 1S9ggrMYQaCHBqfZy8hhOg
# 2. 格式化所有节点(每个节点都要执行)
mkdir -p /opt/kafka/data
/opt/kafka/bin/kafka-storage.sh format \
-t 1S9ggrMYQaCHBqfZy8hhOg \
-c /opt/kafka/config/server.properties \
--ignore-formatted
# 输出:
# Bootstrap metadata: BootstrapMetadata(
# metadataVersionLevel=30, source=format command
# )
# Formatting metadata directory /opt/kafka/data with metadata.version 4.3-IV0.
# 注意:所有节点必须使用相同的 UUID!
# Broker-only 节点 (process.roles=broker) 也需要格式化
2.2.4 启动与验证
bash
# 启动 Kafka(后台守护模式)
nohup /opt/kafka/bin/kafka-server-start.sh \
/opt/kafka/config/server.properties \
> /opt/kafka/kafka.log 2>&1 &
# 检查进程
ps aux | grep kafka.Kafka
# root 18712 64.2 6.9 3746476 241472 ? Sl 12:03 0:03 java ...
# 查看集群状态(KRaft Metadata Quorum)
/opt/kafka/bin/kafka-metadata-quorum.sh \
--bootstrap-server 192.168.0.54:9092 \
describe --status
# 输出:
# ClusterId: 1S9ggrMYQaCHBqfZy8hhOg
# LeaderId: 1
# LeaderEpoch: 1
# HighWatermark: 192
# MaxFollowerLag: 0 ← 所有节点完全同步
# MaxFollowerLagTimeMs: 0
# CurrentVoters: [1, 2, 3]
# CurrentObservers: [4]
2.2.5 创建 Topic 验证
bash
# 创建 Topic
kafka-topics.sh --bootstrap-server 192.168.0.54:9092 \
--create --topic test-basic \
--partitions 4 --replication-factor 3
# 查看 Topic 详情
kafka-topics.sh --bootstrap-server 192.168.0.54:9092 \
--describe --topic test-basic
实战输出:
Topic: test-basic PartitionCount: 4 ReplicationFactor: 3
Partition 0: Leader=3 Replicas=3,4,1 Isr=3,4,1
Partition 1: Leader=4 Replicas=4,1,2 Isr=4,1,2
Partition 2: Leader=1 Replicas=1,2,3 Isr=1,2,3
Partition 3: Leader=2 Replicas=2,3,4 Isr=2,3,4
关键观察:
- 4 个分区的 Leader 分布在 4 个 Broker(3, 4, 1, 2)→ 负载均衡 ✓
- 所有分区的 ISR = Replicas → 副本完全同步 ✓
- Replication Factor = 3,每个分区有 3 个副本 ✓
第三章:Kafka 核心 API 详解
3.1 Producer API
3.1.1 Producer 配置参数详解
java
Properties props = new Properties();
// bootstrap.servers --- Broker 地址列表
// 生产者用此列表发现集群所有 Broker
// 只需提供部分节点,客户端会自动发现全部
// 建议提供 2-3 个节点以防单点故障
props.put("bootstrap.servers", "192.168.0.54:9092,192.168.0.228:9092");
// key.serializer --- Key 序列化器
// 必须实现 org.apache.kafka.common.serialization.Serializer
// 常用:StringSerializer, IntegerSerializer, BytesSerializer
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// value.serializer --- Value 序列化器
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// acks --- 确认机制
// 0: 不等待确认,最快但可能丢消息
// 1: 等待 Leader 确认,默认值
// all (-1): 等待所有 ISR 确认,最安全
props.put("acks", "all");
// retries --- 重试次数(Kafka 3.x+ 默认 Integer.MAX_VALUE)
props.put("retries", 3);
// batch.size --- 批量发送大小(字节)
// 多条消息打包成一个请求发送
// 默认 16384 (16KB)
props.put("batch.size", 16384);
// linger.ms --- 批量等待时间(毫秒)
// 延迟发送以等待更多消息凑批
// 默认 0(立即发送)
// 设为 5-10ms 可在吞吐和延迟间取得平衡
props.put("linger.ms", 5);
// buffer.memory --- 生产者总缓冲区大小
// 默认 33554432 (32MB)
props.put("buffer.memory", 33554432);
// compression.type --- 压缩算法
// none: 不压缩
// gzip: 高压缩率,CPU 开销大
// snappy: 平衡压缩率和速度
// lz4: 快速压缩,推荐
// zstd: 最高压缩率
props.put("compression.type", "lz4");
// max.request.size --- 单次请求最大大小(默认 1MB)
props.put("max.request.size", 1048576);
3.1.2 发送消息方式
java
import org.apache.kafka.clients.producer.*;
// === 方式 1: 发后即忘 (Fire-and-Forget) ===
producer.send(new ProducerRecord<>("topic", "key", "value"));
// 不关心结果,可能丢失消息
// === 方式 2: 同步发送 (Sync) ===
try {
RecordMetadata meta = producer.send(
new ProducerRecord<>("topic", "key", "value")
).get(); // 阻塞等待结果
System.out.printf("offset=%d, partition=%d%n",
meta.offset(), meta.partition());
} catch (Exception e) {
e.printStackTrace();
}
// === 方式 3: 异步发送 (Async with Callback) ===
producer.send(new ProducerRecord<>("topic", "key", "value"),
new Callback() {
@Override
public void onCompletion(RecordMetadata meta, Exception e) {
if (e != null) {
// 发送失败
System.err.println("Send failed: " + e.getMessage());
} else {
// 发送成功
System.out.printf("Sent to partition=%d offset=%d%n",
meta.partition(), meta.offset());
}
}
}
);
3.1.3 Python 客户端示例
python
from kafka import KafkaProducer
import json
# === 基础生产者 ===
producer = KafkaProducer(
bootstrap_servers=['192.168.0.54:9092', '192.168.0.228:9092'],
value_serializer=lambda v: json.dumps(v).encode(),
key_serializer=lambda k: k.encode() if k else None,
acks='all' # 等待所有副本确认
)
# 发送消息
future = producer.send(
'test-basic',
key='user-0',
value={'user': 'user-0', 'msg_id': 0, 'data': 'python-test'}
)
# 获取发送结果(同步等待)
metadata = future.get(timeout=10)
print(f'Partition: {metadata.partition}, Offset: {metadata.offset}')
producer.flush()
producer.close()
实战输出:
Sent: key=user-0 -> partition=3, offset=0
Sent: key=user-1 -> partition=0, offset=10
Sent: key=user-2 -> partition=0, offset=11
Sent: key=user-0 -> partition=3, offset=1 ← 相同 Key 返回同一分区
Sent: key=user-1 -> partition=0, offset=12
Sent: key=user-2 -> partition=0, offset=13
Sent: key=user-0 -> partition=3, offset=2
Sent: key=user-1 -> partition=0, offset=14
Sent: key=user-2 -> partition=0, offset=15
Sent: key=user-0 -> partition=3, offset=3
3.1.4 幂等性配置(Idempotence)
properties
# 幂等性生产者 --- 保证 exactly-once 语义(单分区)
# 开启后自动设置: acks=all, retries=MAX, max.in.flight.requests.per.connection≤5
enable.idempotence=true
# 原理:每个生产者分配 PID (Producer ID),每条消息带 Sequence Number
# Broker 根据 <PID, Partition, SeqNum> 去重
3.1.5 事务支持(Transaction)
java
// 1. 配置事务 ID
props.put("transactional.id", "my-transactional-id");
// 2. 初始化事务
producer.initTransactions();
// 3. 开始事务
producer.beginTransaction();
try {
producer.send(new ProducerRecord<>("topic-a", "key", "value"));
producer.send(new ProducerRecord<>("topic-b", "key", "value"));
// 4. 提交事务
producer.commitTransaction();
} catch (Exception e) {
// 5. 回滚事务
producer.abortTransaction();
}
3.1.6 自定义分区器(Partitioner)
java
public class CustomPartitioner implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
// 自定义分区逻辑
// 例如:特定 Key 固定发往 Partition 0
if ("VIP".equals(key)) {
return 0;
}
// 其他 Key 使用默认哈希
return Math.abs(key.hashCode()) % cluster.partitionCountForTopic(topic);
}
@Override
public void close() {}
@Override
public void configure(Map<String, ?> configs) {}
}
// 使用自定义分区器
props.put("partitioner.class", "com.example.CustomPartitioner");
3.2 Consumer API
3.2.1 Consumer 配置参数详解
java
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.0.54:9092");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// group.id --- 消费者组 ID
// 同一个 Group 的消费者共享分区分配
props.put("group.id", "my-consumer-group");
// auto.offset.reset --- 无初始 Offset 时的策略
// earliest: 从最早的消息开始(相当于 --from-beginning)
// latest: 从最新的消息开始(默认,只消费新消息)
// none: 没有 offset 时抛异常
props.put("auto.offset.reset", "earliest");
// enable.auto.commit --- 是否自动提交 Offset
// true: 自动提交(默认),简单但可能重复消费
// false: 手动提交,精确控制
props.put("enable.auto.commit", "false");
// auto.commit.interval.ms --- 自动提交间隔(默认 5000ms)
props.put("auto.commit.interval.ms", "5000");
// max.poll.records --- 单次 poll() 最大返回记录数
// 默认 500,根据消息处理速度调整
props.put("max.poll.records", "500");
// max.poll.interval.ms --- 两次 poll() 最大间隔
// 超过此时间消费者被认为"失联",触发重平衡
// 默认 300000 (5分钟)
props.put("max.poll.interval.ms", "300000");
// session.timeout.ms --- 会话超时
// 消费者在此时间内未发送心跳,被认为已下线
// 默认 45000 (45秒)
props.put("session.timeout.ms", "45000");
// heartbeat.interval.ms --- 心跳间隔
// 应小于 session.timeout.ms 的 1/3
// 默认 3000 (3秒)
props.put("heartbeat.interval.ms", "3000");
// fetch.min.bytes --- 最小拉取字节数
// Broker 等待积累到此字节数再返回(可减少请求次数)
props.put("fetch.min.bytes", "1");
// fetch.max.wait.ms --- 最大等待时间
// 配合 fetch.min.bytes,到达时间即使不足也会返回
props.put("fetch.max.wait.ms", "500");
3.2.2 消费消息示例
java
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
// 订阅方式 1: subscribe --- 自动分区分配(推荐)
consumer.subscribe(Arrays.asList("topic-a", "topic-b"));
// 订阅方式 2: assign --- 手动指定分区
TopicPartition partition0 = new TopicPartition("topic-a", 0);
consumer.assign(Arrays.asList(partition0));
// 消息拉取循环
try {
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("topic=%s, partition=%d, offset=%d, key=%s, value=%s%n",
record.topic(), record.partition(),
record.offset(), record.key(), record.value());
}
// 手动提交 Offset
consumer.commitSync();
}
} finally {
consumer.close();
}
3.2.3 Python 消费者示例
python
from kafka import KafkaConsumer
import json
consumer = KafkaConsumer(
'test-basic',
bootstrap_servers='192.168.0.54:9092',
auto_offset_reset='earliest', # 从最早消息开始
enable_auto_commit=False, # 手动提交
group_id='python-test-group',
value_deserializer=lambda v: json.loads(v.decode()),
key_deserializer=lambda k: k.decode() if k else None,
max_poll_records=5
)
for msg in consumer:
print(f'partition={msg.partition} offset={msg.offset} '
f'key={msg.key} value={msg.value}')
3.2.4 Offset 管理
java
// === 自动提交 (默认) ===
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "5000"); // 5秒提交一次
// 优点:简单;缺点:可能重复消费
// === 手动同步提交 ===
consumer.commitSync();
// 阻塞直到提交完成,保证提交成功,但影响吞吐
// === 手动异步提交 ===
consumer.commitAsync(new OffsetCommitCallback() {
@Override
public void onComplete(Map<TopicPartition, OffsetAndMetadata> offsets,
Exception e) {
if (e != null) {
System.err.println("Commit failed: " + e.getMessage());
}
}
});
// 不阻塞,吞吐高,但可能提交失败
// === 提交特定 Offset ===
Map<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>();
offsets.put(new TopicPartition("topic", 0),
new OffsetAndMetadata(12345L));
consumer.commitSync(offsets);
3.3 Admin API
java
import org.apache.kafka.clients.admin.*;
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.0.54:9092");
AdminClient admin = AdminClient.create(props);
// 创建 Topic
NewTopic newTopic = new NewTopic("my-topic", 4, (short) 3);
admin.createTopics(Arrays.asList(newTopic)).all().get();
// 列出 Topic
ListTopicsResult topics = admin.listTopics();
topics.listings().get().forEach(t -> System.out.println(t.name()));
// 描述 Topic
DescribeTopicsResult desc = admin.describeTopics(Arrays.asList("test-basic"));
desc.all().get().forEach((name, info) -> {
System.out.printf("Topic: %s, Partitions: %d, RF: %d%n",
name, info.partitions().size(),
info.partitions().get(0).replicas().size());
});
// 增加分区
admin.createPartitions(
Map.of("my-topic", NewPartitions.increaseTo(8))
).all().get();
// 删除 Topic
admin.deleteTopics(Arrays.asList("old-topic")).all().get();
admin.close();
3.4 Streams API
Kafka Streams 是用于构建流处理应用的 Java 库:
Kafka Streams 架构:
Source Topic ──► [Stream Processor] ──► [State Store]
│
├── map / filter / flatMap
├── join / leftJoin
├── aggregate / reduce
└── window (Tumbling/Hopping/Session)
│
▼
Sink Topic
java
// Kafka Streams 示例:单词计数
StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> source = builder.stream("input-topic");
KTable<String, Long> counts = source
.flatMapValues(text -> Arrays.asList(text.toLowerCase().split(" ")))
.groupBy((key, word) -> word)
.count();
counts.toStream().to("output-topic");
KafkaStreams streams = new KafkaStreams(builder.build(), config);
streams.start();
第四章:Kafka 核心机制深入
4.1 存储机制
4.1.1 日志存储结构(Log Segment)
Kafka 日志存储目录结构:
/opt/kafka/data/test-basic-0/
├── 00000000000000000000.log ← 消息数据文件
├── 00000000000000000000.index ← 偏移量索引
├── 00000000000000000000.timeindex ← 时间戳索引
├── leader-epoch-checkpoint ← Leader Epoch 检查点
└── partition.metadata ← 分区元数据
每个 Partition 对应一个目录,内部由多个 Log Segment 组成:
[Log Segment 0] [Log Segment 1] [Log Segment 2] [Active Segment]
.log: 0 ~ 999 .log: 1000~1999 .log: 2000~2999 .log: 3000~...
.index .index .index (正在写入)
.timeindex .timeindex .timeindex
Segment 文件命名规则:以该 Segment 第一条消息的 Offset 为基准(20位数字,左补0)
实战验证:
# 查看实际存储结构
ls -la /opt/kafka/data/test-basic-0/
-rw-r--r-- 00000000000000000000.index 10485760 ← 10MB 索引文件
-rw-r--r-- 00000000000000000000.log 366 ← 实际消息数据
-rw-r--r-- 00000000000000000000.timeindex 10485756 ← 10MB 时间索引
-rw-r--r-- leader-epoch-checkpoint 8
-rw-r--r-- partition.metadata 43
4.1.2 索引文件
偏移量索引 (Offset Index):
作用:根据 Offset 快速定位消息在 .log 文件中的物理位置
索引结构 (稀疏索引,不是每条消息都有):
┌──────────────────────────────────────┐
│ Relative Offset │ Physical Position │
├──────────────────┼───────────────────┤
│ 0 │ 0 │
│ 100 │ 8192 │
│ 200 │ 16384 │
│ ... │ ... │
└──────────────────┴───────────────────┘
查找 Offset=150 的流程:
1. 二分查找索引 → 定位到 Relative Offset=100, Position=8192
2. 从 .log 文件 Position=8192 开始顺序扫描
3. 找到 Offset=150 的消息
时间戳索引 (Time Index):
作用:根据时间戳快速定位 Offset
索引结构:
┌──────────────────────────────────────┐
│ Timestamp (ms) │ Relative Offset │
├────────────────────┼─────────────────┤
│ 1717228800000 │ 0 │
│ 1717228801000 │ 100 │
│ ... │ ... │
└────────────────────┴─────────────────┘
4.1.3 零拷贝技术(Zero Copy)
传统文件传输(4次拷贝,4次上下文切换):
Disk → Read Buffer → User Buffer → Socket Buffer → NIC
↑ ↑ ↑ ↑ ↑
1 2拷贝 3拷贝 4拷贝
Kafka 零拷贝 (sendfile 系统调用,2次拷贝,2次上下文切换):
Disk → Read Buffer → Socket Buffer → NIC
↑ ↑ ↑ ↑
1 (DMA) (DMA)
节省 CPU 拷贝,大幅提升吞吐量 ⚡
4.1.4 页缓存(Page Cache)优化
Kafka 重度依赖操作系统的 Page Cache:
写路径:
Producer → Kafka 进程 → OS Page Cache → 磁盘 (异步刷盘)
↑
写入即返回,不等待磁盘
读路径:
Consumer → Kafka 进程 → OS Page Cache (命中) → 零拷贝发送
↑
热点数据在内存中,无磁盘 IO
优化效果:
- Kafka 不自己管理缓存,交由 OS
- 数据写入 Page Cache 即返回确认
- 消费者读取时大概率命中 Page Cache
- 剩余可用内存全部用作 Page Cache
4.1.5 文件刷盘策略
properties
# Kafka 依赖 OS 后台刷盘,不强制同步写入
# log.flush.interval.messages --- 多少条消息刷盘一次
# 默认 Long.MAX_VALUE(不按消息条数刷盘)
log.flush.interval.messages=10000
# log.flush.interval.ms --- 刷盘间隔(毫秒)
# 默认 Long.MAX_VALUE(不按时间刷盘)
log.flush.interval.ms=1000
# ⚠️ 建议:使用默认值,依赖 OS 后台刷盘 + 副本机制保证可靠性
# 强制刷新会严重影响性能!
4.2 分区与副本机制
4.2.1 分区策略与优势
分区 (Partition) 是 Kafka 存储和并行处理的基本单元:
优势 1 --- 水平扩展:
Topic 数据分散在多个 Broker 上,突破单机磁盘限制
优势 2 --- 并行处理:
多个消费者并行消费不同分区,提升吞吐量
优势 3 --- 负载均衡:
Leader 分布在多台 Broker,避免单点热点
分区数量选择指南:
┌─────────────┬──────────────┐
│ 场景 │ 建议分区数 │
├─────────────┼──────────────┤
│ 低吞吐 Topic │ 3-6 │
│ 中吞吐 Topic │ 6-12 │
│ 高吞吐 Topic │ 12-24 │
│ 极高吞吐 │ 24-100+ │
└─────────────┴──────────────┘
⚠️ 注意:分区数越多,Leader 选举和文件句柄开销越大
4.2.2 副本机制(Leader、Follower)
┌──────────────────────────────────────────────────────────┐
│ Partition 0, RF=3 │
│ │
│ ┌─────────────────┐ │
│ │ Broker 3 │ ← Leader │
│ │ (处理所有读写) │ │
│ └────────┬────────┘ │
│ │ 数据复制 (Fetch Request) │
│ ┌─────┴─────┐ │
│ ▼ ▼ │
│ ┌────────┐ ┌────────┐ │
│ │Broker 4│ │Broker 1│ ← Followers (只从 Leader 同步) │
│ └────────┘ └────────┘ │
│ │
│ ISR = [3, 4, 1] ← 所有在同步的副本 │
│ │
│ 如果 Broker 3 故障: │
│ → Controller 从 ISR 中选举新 Leader (4 或 1) │
│ → 新 Leader 接管读写 │
│ → 客户端自动重连 │
└──────────────────────────────────────────────────────────┘
4.2.3 ISR(In-Sync Replicas)机制
ISR 是与 Leader 保持同步的副本集合。
加入 ISR 条件:
- Follower 在 replica.lag.time.max.ms (默认 30s) 内向 Leader 发送 Fetch 请求
- Follower 的 LEO 与 Leader 的 LEO 差距在可接受范围
移出 ISR 条件:
- 超过 replica.lag.time.max.ms 未发送 Fetch 请求
- LEO 落后太多(由 replica.lag.max.messages 控制,4.x 已弃用)
实战 ISR 状态:
Topic: test-basic Partition: 0 Leader: 3 Isr: 3,4,1 ✓ 全部同步
Topic: test-basic Partition: 1 Leader: 4 Isr: 4,1,2 ✓ 全部同步
Topic: test-basic Partition: 2 Leader: 1 Isr: 1,2,3 ✓ 全部同步
Topic: test-basic Partition: 3 Leader: 2 Isr: 2,3,4 ✓ 全部同步
4.2.4 HW(High Watermark)与 LEO(Log End Offset)
HW 和 LEO 是 Kafka 副本机制的核心概念:
LEO (Log End Offset) --- 副本下一条待写入消息的 Offset
HW (High Watermark) --- 消费者可见的最高 Offset(所有 ISR 都已确认)
┌─────────────────────────────────────────────┐
│ Partition 日志 │
│ │
│ 消息: [0] [1] [2] [3] [4] [5] [6] [7] ... │
│ │ │ │ │ │
│ │ 已提交 │ │ 未提交 │ │
│ │ (消费者可见) │ │ (消费者不可见) │
│ │ │ │ │ │
│ Offset: 0 HW=4 LEO=8 │
│ │
│ Leader: LEO=8, HW=4 │
│ Follower: LEO=6, HW=4 ← 正在同步 5,6 │
│ │
│ 当 Follower 同步到 5,6 后: │
│ Leader 推进 HW → 6 │
└─────────────────────────────────────────────┘
HW 的作用:
1. 消费可见性控制 --- 只有 HW 之前的消息才对消费者可见
2. 故障恢复 --- 新 Leader 从 HW 开始,避免数据不一致
3. 配合 min.insync.replicas 保证消息不丢失
4.2.5 副本同步流程
Producer 写入 + 副本同步完整流程 (acks=all, min.insync.replicas=2):
Producer Leader (3) Follower (4) Follower (1)
│ │ │ │
│ 1. Produce Request │ │ │
│──────────────────────►│ │ │
│ │ 2. Append to Log │ │
│ │ LEO: 7→8 │ │
│ │ │ │
│ │ 3. Follower Fetch │ │
│ │◄──────────────────────│ (拉取模式) │
│ │◄────────────────────────────────────────│
│ │ │ │
│ │ 4. Return Records │ │
│ │──────────────────────►│ LEO: 5→8 │
│ │────────────────────────────────────────►│ LEO: 5→8
│ │ │ │
│ │ 5. HW 推进: 6→8 │ │
│ │ (所有 ISR LEO≥8) │ │
│ │ │ │
│ 6. ACK (offset=8) │ │ │
│◄──────────────────────│ │ │
│ │ │ │
关键点:
- Follower 使用拉取模式(Fetch Request),不是 Leader 推送
- HW 在所有 ISR 副本同步后统一推进
- min.insync.replicas=2 意味着 Leader + 至少 1 个 Follower 确认即可
4.3 消费者组与重平衡
4.3.1 消费者组概念
┌─────────────────────────────────────────────────────────────┐
│ Consumer Group 示例 │
│ │
│ Group: "order-processor" (3 Consumer) │
│ │
│ Topic: orders (4 Partitions) │
│ │
│ Consumer A ── Partition 0, Partition 1 │
│ Consumer B ── Partition 2 │
│ Consumer C ── Partition 3 │
│ │
│ 规则: │
│ 1. 同一 Group 内,每个 Partition 只能被一个 Consumer 消费 │
│ 2. 一个 Consumer 可以消费多个 Partition │
│ 3. Consumer 数量 ≤ Partition 数量(超出则空闲) │
│ 4. 不同 Group 之间完全隔离 │
└─────────────────────────────────────────────────────────────┘
4.3.2 分区分配策略
Range (默认):
按 Topic 分区编号范围分配给消费者
例: 8 分区, 3 消费者 → A(0-2), B(3-5), C(6-7)
问题:可能导致分配不均
RoundRobin:
轮询分配,更均衡
例: A(0,3,6), B(1,4,7), C(2,5)
注意: 需要所有消费者订阅相同 Topic
Sticky (合作式,推荐):
基于 RoundRobin,但尽可能保持原有分配
重平衡时只移动必要的分区,减少暂停时间
配置: partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor
4.3.3 重平衡触发条件
重平衡 (Rebalance) 触发条件:
1. 新消费者加入 Consumer Group
2. 已有消费者离开(心跳超时 / 主动离开)
3. Topic 分区数变化(增加分区)
4. 消费者处理时间超过 max.poll.interval.ms
5. Consumer Group 订阅的 Topic 被创建/删除
重平衡过程:
┌──────────────────────────────────────────────────────┐
│ 1. Group Coordinator 检测到消费者变更 │
│ 2. 通知所有消费者重新加入 Group (JoinGroup) │
│ 3. 选举 Group Leader (第一个加入的消费者) │
│ 4. Leader 执行分区分配方案 (PartitionAssignor) │
│ 5. Leader 将分配结果发送给 Coordinator (SyncGroup) │
│ 6. Coordinator 将分配结果下发给各消费者 │
│ 7. 消费者收到新分配,继续消费 │
│ │
│ ⚠️ 重平衡期间整个 Group 暂停消费!(STW) │
│ ⚠️ 合作式协议 (CooperativeStickyAssignor) 可减少暂停 │
└──────────────────────────────────────────────────────┘
4.3.4 避免频繁重平衡策略
properties
# 1. 增大 session.timeout.ms
# 防止网络抖动导致的短暂"失联"
session.timeout.ms=60000 # 默认 45s
# 2. 增大 max.poll.interval.ms
# 防止消息处理时间过长被踢出 Group
max.poll.interval.ms=600000 # 默认 5min,生产可设 10min+
# 3. 控制 max.poll.records
# 防止一次拉取过多消息导致处理超时
max.poll.records=200 # 默认 500
# 4. 使用合作式分配策略
partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor
# 5. group.initial.rebalance.delay.ms
# 控制首次重平衡延迟,避免频繁启动时的重平衡
group.initial.rebalance.delay.ms=3000 # 默认 0
4.4 控制器(Controller)
4.4.1 Controller 选举机制
在 KRaft 模式下,Controller 由 Raft 协议选举产生:
┌─────────────────────────────────────────────────────────┐
│ Controller 选举 │
│ │
│ Quorum: [Node 1, Node 2, Node 3] │
│ │
│ 启动时:所有节点发起 Raft Leader 选举 │
│ ┌──────────────────────────────────────────────┐ │
│ │ Node 1: 发起投票 (Term=1) │ │
│ │ Node 2: 投票给 Node 1 │ │
│ │ Node 3: 投票给 Node 1 │ │
│ │ → Node 1 获得多数票,成为 Active Controller │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 实战状态: │
│ LeaderId: 1 ← Node 1 是 Active Controller │
│ LeaderEpoch: 1 │
│ CurrentVoters: [1, 2, 3] │
│ CurrentObservers: [4] │
└─────────────────────────────────────────────────────────┘
4.4.2 Controller 职责
Active Controller 的核心职责:
1. 分区管理
- 创建/删除 Topic
- 增加分区
- 分区副本分配
2. Leader 选举
- 监控 Broker 故障
- 从 ISR 中选举新 Leader
- 通知所有 Broker 新的 Leader 信息
3. 集群管理
- Broker 加入/离开处理
- 维护集群元数据
4. 再平衡
- 副本迁移(kafka-reassign-partitions.sh)
- Preferred Leader 选举
4.4.3 Controller 故障转移
Controller 故障转移流程:
1. Follower 检测到 Leader 心跳超时
2. Follower 发起新一轮选举(LeaderEpoch++)
3. 获得多数票的节点成为新 Active Controller
4. 新 Controller 读取 Metadata Topic 恢复状态
5. 新 Controller 接管所有管理职责
故障转移时间:通常 < 3 秒(取决于配置的超时时间)
第五章:Kafka 生产者详解
5.1 消息发送流程
Producer 内部发送流程:
┌──────────────────────────────────────────────────────────────┐
│ Producer 发送流程 │
│ │
│ 1. send(record) │
│ │ │
│ ▼ │
│ 2. Serializer (Key + Value 序列化) │
│ │ │
│ ▼ │
│ 3. Partitioner (选择目标分区) │
│ │ - Key 存在 → hash(key) % num_partitions │
│ │ - Key 为 null → Round-Robin / Sticky │
│ │ │
│ ▼ │
│ 4. RecordAccumulator (消息缓冲区) │
│ │ - 按 <Topic, Partition> 分组 │
│ │ - 每个分区一个 Batch (Deque) │
│ │ - batch.size 控制 Batch 大小 │
│ │ - buffer.memory 控制总缓冲区 │
│ │ │
│ ▼ │
│ 5. Sender Thread (发送线程) │
│ │ - 检查 Batch 是否就绪 (full / linger.ms) │
│ │ - 构建 ProduceRequest │
│ │ - 发送到 Broker Leader │
│ │ │
│ ▼ │
│ 6. Broker 处理 │
│ │ - 写入 Leader 日志 │
│ │ - 副本同步(异步) │
│ │ - 返回 ProduceResponse (根据 acks) │
│ │ │
│ ▼ │
│ 7. Callback (如果配置) / Future.get() │
│ - Retry (如果失败且可重试) │
│ - 返回 RecordMetadata (partition, offset, timestamp) │
└──────────────────────────────────────────────────────────────┘
5.2 关键参数配置
5.2.1 acks 参数详解
acks=0:
Producer 发送后不等待任何确认
→ 最快,但消息可能丢失(网络问题/Broker 故障)
→ 适合:指标收集、日志(容忍少量丢失)
acks=1 (默认):
Producer 等待 Leader 确认写入
→ 平衡性能和可靠性
→ 如果 Leader 写入后、Follower 同步前故障 → 消息丢失
→ 适合:大多数业务场景
acks=all (-1):
Producer 等待所有 ISR 确认写入
→ 最可靠,配合 min.insync.replicas 使用
→ 如果 ISR 数量 < min.insync.replicas → 写入失败
→ 适合:金融/交易等不能丢消息的场景
性能对比(实测,2vCPU/4GiB,跨公网):
acks=0: ~20,000 msg/s
acks=1: ~13,675 msg/s (本次实测)
acks=all: ~5,000 msg/s (估算)
5.2.2 重试机制
properties
# retries --- 重试次数
# 3.x+ 默认 Integer.MAX_VALUE(无限重试)
# 生产环境建议设置有限次数
retries=3
# retry.backoff.ms --- 重试间隔(毫秒)
retry.backoff.ms=100
# delivery.timeout.ms --- 投递超时(包含重试)
# 默认 120000 (2分钟)
delivery.timeout.ms=120000
# 重试可能导致消息乱序 → 设置 max.in.flight.requests.per.connection=1
max.in.flight.requests.per.connection=5 # 默认,≤5 时配合幂等性可保证顺序
5.2.3 批处理优化
properties
# batch.size --- 批次大小(字节)
# 默认 16384 (16KB),可设大一些提升吞吐
batch.size=32768 # 32KB
# linger.ms --- 延迟发送(毫秒)
# 设为 0 立即发送(低延迟,低吞吐)
# 设为 5-10ms 等待更多消息凑批(高吞吐,略高延迟)
linger.ms=5
# buffer.memory --- 生产者总缓冲区(字节)
# 默认 33554432 (32MB)
# 如果生产速度 > 发送速度,缓冲区满后会阻塞 send()
buffer.memory=67108864 # 64MB
# 调优黄金法则:
# 高吞吐场景 → 增大 batch.size, linger.ms
# 低延迟场景 → 减小 batch.size, linger.ms=0
5.2.4 压缩配置
压缩算法对比:
┌──────────┬──────────┬──────────┬──────────┐
│ 算法 │ 压缩率 │ CPU 开销 │ 适用场景 │
├──────────┼──────────┼──────────┼──────────┤
│ none │ 1x │ 无 │ 不压缩 │
│ gzip │ 最高 │ 最高 │ 带宽有限 │
│ snappy │ 中等 │ 低 │ 平衡选择 │
│ lz4 │ 中等 │ 最低 │ 推荐首选 │
│ zstd │ 高 │ 中等 │ 新项目 │
└──────────┴──────────┴──────────┴──────────┘
推荐:compression.type=producer(保留生产者原始压缩)
5.3 可靠性保证
5.3.1 消息不丢失配置(Producer 端)
properties
# 消息不丢失的完整 Producer 配置
acks=all # 所有 ISR 确认
enable.idempotence=true # 幂等性
max.in.flight.requests.per.connection=5 # 配合幂等性保证顺序
retries=2147483647 # 无限重试(默认值)
compression.type=lz4 # 压缩
5.3.2 消息不丢失配置(Broker 端)
properties
# Broker 端:可靠性配置
default.replication.factor=3 # 3 副本
min.insync.replicas=2 # 最少 2 个 ISR 确认
offsets.topic.replication.factor=3 # Offset Topic 3 副本
transaction.state.log.replication.factor=3 # 事务日志 3 副本
transaction.state.log.min.isr=2
# 禁用 Unclean Leader 选举(数据一致性优先)
unclean.leader.election.enable=false
5.3.3 消息顺序性保证
Kafka 消息顺序性:
✓ 分区内有序 --- 同一分区内消息按 Offset 严格有序
✗ 跨分区无序 --- 不同分区之间无顺序保证
✗ 重试可能乱序 --- 除非 max.in.flight.requests.per.connection=1
全局有序方案:
1. 单分区 Topic → 全局有序,但吞吐受限
2. Key 路由 → 同一 Key 的消息有序(相同业务 ID)
3. 幂等生产 → 配合 max.in.flight ≤ 5 保证顺序
5.4 性能优化
properties
# 高性能 Producer 配置模板
# 批处理
batch.size=65536 # 64KB 批次
linger.ms=10 # 10ms 延迟凑批
buffer.memory=134217728 # 128MB 缓冲区
# 压缩
compression.type=lz4 # 快速压缩
# 网络
max.in.flight.requests.per.connection=5 # 允许5个未确认请求
# 可靠性(在不丢消息的前提下优化性能)
acks=1 # 仅 Leader 确认
retries=3 # 有限重试
第六章:Kafka 消费者详解
6.1 消费流程
Consumer 消费流程:
1. Consumer 初始化
- 加载配置
- 连接 Bootstrap Server
- 获取集群元数据
2. 加入 Consumer Group
- 发送 JoinGroup 请求
- 选举 Group Leader
- 接收分区分配方案
3. 消息拉取 (Poll Loop)
┌─────────────────────────────────┐
│ while (true) { │
│ records = consumer.poll(1s) │ ← 拉取消息
│ process(records) │ ← 处理消息
│ consumer.commitSync() │ ← 提交 Offset
│ } │
└─────────────────────────────────┘
4. 偏移量提交
- 自动提交(定时 5s)
- 手动提交(commitSync / commitAsync)
6.2 关键参数配置
properties
# === 拉取控制 ===
# fetch.min.bytes --- 最小拉取字节数
# Broker 积累到此字节数后再返回给消费者
# 默认 1(有数据立即返回)
fetch.min.bytes=1024 # 至少 1KB
# fetch.max.bytes --- 最大拉取字节数
# 单次 fetch 请求最大返回数据量
# 默认 52428800 (50MB)
fetch.max.bytes=52428800
# fetch.max.wait.ms --- 最大拉取等待时间
# 配合 fetch.min.bytes,到达此时间即使字节数不足也返回
fetch.max.wait.ms=500
# max.partition.fetch.bytes --- 单分区最大拉取字节数
# 默认 1048576 (1MB)
max.partition.fetch.bytes=1048576
# === 消费控制 ===
# max.poll.records --- 单次 poll 最多返回记录数
# 默认 500,建议根据消息大小和处理能力调整
max.poll.records=500
# max.poll.interval.ms --- 两次 poll 最大间隔
# 超过此时间消费者被认为失联,触发重平衡
# 默认 300000 (5min)
max.poll.interval.ms=600000 # 10min
# === 会话控制 ===
# session.timeout.ms --- 会话超时(默认 45s)
session.timeout.ms=45000
# heartbeat.interval.ms --- 心跳间隔(默认 3s)
# 应 < session.timeout.ms / 3
heartbeat.interval.ms=3000
# === Offset 策略 ===
# auto.offset.reset --- 无 Offset 时的初始策略
auto.offset.reset=earliest # earliest / latest / none
# enable.auto.commit --- 自动提交
enable.auto.commit=false # 推荐 false,手动提交
6.3 偏移量(Offset)管理
6.3.1 __consumer_offsets 主题
__consumer_offsets 是 Kafka 内部 Topic,存储所有 Consumer Group 的 Offset:
┌──────────────────────────────────────────────────────┐
│ __consumer_offsets │
│ │
│ Key: <GroupID, Topic, Partition> │
│ Value: <Offset, Metadata, Timestamp> │
│ │
│ 示例: │
│ Key: (order-processor, orders, 0) │
│ Value: (offset=12345, metadata="", timestamp=...) │
│ │
│ 特点: │
│ - 默认 50 个分区 │
│ - 日志压缩策略 (compact) │
│ - 副本因子由 offsets.topic.replication.factor 决定 │
└──────────────────────────────────────────────────────┘
6.3.2 Offset 提交方式对比
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ 提交方式 │ 可靠性 │ 吞吐量 │ 适用场景 │
├──────────────┼──────────────┼──────────────┼──────────────┤
│ 自动提交 │ 低 │ 高 │ 简单场景 │
│ 手动同步提交 │ 高 │ 低(阻塞) │ 金融/支付 │
│ 手动异步提交 │ 中 │ 高 │ 推荐首选 │
│ 特定Offset │ 最高 │ 自定义 │ 精准控制 │
└──────────────┴──────────────┴──────────────┴──────────────┘
// 推荐模式:先处理,再异步提交
consumer.poll()
→ process(records) // 成功处理
→ commitAsync() // 异步提交
→ callback 中检查失败 // 失败告警
6.4 消费者组管理
Consumer Group 内部协调:
┌──────────────────────────────────────────────────────────┐
│ Group Coordinator │
│ (某个 Broker) │
│ │
│ 职责: │
│ - 维护 Group 成员列表 │
│ - 触发/协调 Rebalance │
│ - 接收分区分配方案 │
│ - 管理 Offset 提交 │
│ │
│ Group Leader (某个 Consumer,不是 Broker) │
│ 职责: │
│ - 执行分区分配策略 (PartitionAssignor) │
│ - 将分配方案发送给 Coordinator │
└──────────────────────────────────────────────────────────┘
Consumer Group 状态转换:
Empty → PreparingRebalance → CompletingRebalance → Stable
↑ │
└────────── 成员变更 ────────────────┘
6.5 消费者性能优化
java
// === 多线程消费方案 ===
// 方案 1: 每个线程一个 Consumer(推荐)
// 每个 Consumer 独立消费不同 Partition
// 优点:简单,线程安全
// 缺点:线程数 ≤ 分区数
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 4; i++) {
executor.submit(() -> {
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("topic"));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));
for (ConsumerRecord<String, String> record : records) {
process(record); // 同步处理
}
consumer.commitSync();
}
});
}
// 方案 2: 单 Consumer + 多处理线程
// 一个 Consumer poll,多个工作线程处理
// 缺点:Offset 管理复杂,可能丢失消息
第七章:Kafka 集群管理
7.1 集群扩容与缩容
7.1.1 Broker 扩容
bash
# 1. 准备新节点(安装 Kafka,配置 server.properties)
# node.id 必须唯一(选择未使用的 ID)
# controller.quorum.voters 中不需要添加纯 Broker 节点
# 2. 格式化存储(使用相同的集群 UUID)
kafka-storage.sh format -t 1S9ggrMYQaCHBqfZy8hhOg \
-c /opt/kafka/config/server.properties
# 3. 启动新 Broker
nohup kafka-server-start.sh /opt/kafka/config/server.properties &
# 4. 验证新 Broker 加入
kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --status
# 检查 CurrentObservers 中是否包含新节点
7.1.2 分区重新分配
bash
# 场景:将现有分区迁移到新 Broker
# 1. 生成迁移计划(JSON 文件)
cat > reassign.json << 'EOF'
{
"topics": [{"topic": "test-basic"}],
"version": 1
}
EOF
# 2. 生成建议的分配方案
kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--topics-to-move-json-file reassign.json \
--broker-list "1,2,3,4" \
--generate
# 3. 执行迁移
kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--reassignment-json-file reassign-execute.json \
--execute
# 4. 验证迁移进度
kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--reassignment-json-file reassign-execute.json \
--verify
7.1.3 Broker 缩容
bash
# 1. 将要下线的 Broker 上的分区迁移到其他 Broker
# (使用上面的 reassign 工具)
# 2. 迁移完成后,停止 Broker
kill <pid>
# 3. 如果下线的 Broker 是 Controller
# → 集群自动执行 Controller 选举(无需手动干预)
# → 检查新的 Active Controller:
kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --status
7.2 Topic 管理
7.2.1 Topic 常用操作
bash
# 创建 Topic
kafka-topics.sh --bootstrap-server localhost:9092 \
--create --topic my-topic \
--partitions 8 --replication-factor 3 \
--config retention.ms=604800000 \
--config cleanup.policy=delete
# 列出 Topic
kafka-topics.sh --bootstrap-server localhost:9092 --list
# 查看详情
kafka-topics.sh --bootstrap-server localhost:9092 \
--describe --topic my-topic
# 增加分区(⚠️ 只能增加不能减少!)
kafka-topics.sh --bootstrap-server localhost:9092 \
--alter --topic my-topic --partitions 12
# 修改配置
kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-name my-topic \
--alter --add-config retention.ms=259200000
# 删除 Topic
kafka-topics.sh --bootstrap-server localhost:9092 \
--delete --topic my-topic
7.2.2 日志清理策略
delete 策略(默认):
根据 retention.ms / retention.bytes 删除旧消息
适用场景:大多数业务消息
compact 策略:
保留每个 Key 的最新值,删除旧版本
适用场景:数据库 CDC、配置更新、状态快照
compact,delete 组合策略:
先压缩,再按时间/大小删除
适用场景:需要追溯变更历史,但保留时间有限
7.3 监控与告警
7.3.1 关键监控指标
┌─────────────────────────────────────────────────────────────┐
│ Kafka 关键监控指标 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Broker 级别: │
│ ├── BytesInPerSec / BytesOutPerSec (吞吐量) │
│ ├── MessagesInPerSec (消息速率) │
│ ├── TotalTimeMs (请求处理延迟) │
│ ├── RequestQueueSize (请求队列深度) │
│ ├── ActiveControllerCount (应为 1) │
│ ├── OfflinePartitionsCount (应为 0) │
│ └── UnderReplicatedPartitions (应为 0) │
│ │
│ Consumer Group 级别: │
│ └── RecordsLag (消费积压,关键!) │
│ │
│ Producer 级别: │
│ ├── record-send-rate (发送速率) │
│ ├── record-error-rate (错误率) │
│ └── request-latency-avg (平均延迟) │
│ │
│ Topic 级别: │
│ ├── BytesInPerSec / BytesOutPerSec │
│ └── Partition 级别 Leader/ISR 状态 │
└─────────────────────────────────────────────────────────────┘
7.3.2 消费者 Lag 监控
bash
# 查看 Consumer Group Lag
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group my-group --describe
# 输出示例:
# GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG
# my-group test-basic 0 15 15 0 ✓
# my-group test-basic 1 12 20 8 ⚠️ 积压
# my-group test-basic 2 8 8 0 ✓
# LAG > 0 → 消费者落后,需要关注
# LAG 持续增长 → 消费者处理能力不足
7.4 备份与恢复
7.4.1 MirrorMaker 2 跨集群复制
MirrorMaker 2 是 Kafka 官方跨集群数据复制工具:
┌──────────────────┐ ┌──────────────────┐
│ DC-A (主集群) │ ──────►│ DC-B (灾备集群) │
│ │ MM2 │ │
│ topic-a │────────►│ A.topic-a │
│ topic-b │────────►│ A.topic-b │
│ │ │ │
│ 消息自动同步 │ │ 保持一致 Offset │
└──────────────────┘ └──────────────────┘
MirrorMaker 2 特性:
- 基于 Kafka Connect 框架
- 支持 Active/Passive 和 Active/Active
- 自动 Offset 同步
- Topic 配置同步
7.4.2 灾难恢复方案
bash
# 数据备份:定时备份日志目录
tar -czf /backup/kafka-data-$(date +%Y%m%d).tar.gz /opt/kafka/data/
# 恢复步骤:
# 1. 停止所有 Broker
# 2. 恢复数据目录
tar -xzf kafka-data-20260601.tar.gz -C /opt/kafka/
# 3. 重新格式化(⚠️ 会丢失数据!如果需要保留数据,跳过此步)
# 4. 按顺序启动 Controller 节点
第八章:Kafka 安全机制
8.1 认证机制
8.1.1 SSL/TLS 加密
properties
# Broker 端 SSL 配置
listeners=SSL://0.0.0.0:9094
advertised.listeners=SSL://公网IP:9094
# SSL 证书配置
ssl.keystore.location=/opt/kafka/ssl/kafka.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/opt/kafka/ssl/kafka.truststore.jks
ssl.truststore.password=changeit
# 客户端 SSL 配置
security.protocol=SSL
ssl.truststore.location=/path/to/client.truststore.jks
ssl.truststore.password=changeit
8.1.2 SASL 认证
properties
# === SASL/PLAIN ===
# Broker 端
listeners=SASL_PLAINTEXT://0.0.0.0:9095
sasl.enabled.mechanisms=PLAIN
sasl.mechanism.inter.broker.protocol=PLAIN
# JAAS 配置文件
KafkaServer {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="admin"
password="admin-secret"
user_admin="admin-secret"
user_producer="producer-secret"
user_consumer="consumer-secret";
};
# === SASL/SCRAM (推荐,密码不传输) ===
# 创建 SCRAM 用户
kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --add-config 'SCRAM-SHA-256=[password=secret]' \
--entity-type users --entity-name admin
8.1.3 完整安全配置
properties
# 多层安全:SSL + SASL
listeners=SASL_SSL://0.0.0.0:9096
advertised.listeners=SASL_SSL://公网IP:9096
security.inter.broker.protocol=SASL_SSL
# SASL 配置
sasl.enabled.mechanisms=SCRAM-SHA-256
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
# SSL 配置
ssl.keystore.location=/opt/kafka/ssl/kafka.keystore.jks
ssl.keystore.password=changeit
ssl.truststore.location=/opt/kafka/ssl/kafka.truststore.jks
ssl.truststore.password=changeit
8.2 授权机制(ACL)
bash
# 添加 ACL --- 允许 producer-user 对 my-topic 有写权限
kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:producer-user \
--operation Write --topic my-topic
# 添加 ACL --- 允许 consumer-user 对 my-group 有读权限
kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:consumer-user \
--operation Read --topic my-topic \
--group my-group
# 查看 ACL
kafka-acls.sh --bootstrap-server localhost:9092 --list
# 删除 ACL
kafka-acls.sh --bootstrap-server localhost:9092 \
--remove --allow-principal User:producer-user \
--operation Write --topic my-topic
8.3 网络安全
properties
# listener.security.protocol.map
# 定义可用协议名到安全协议的映射
listener.security.protocol.map=\
PLAINTEXT:PLAINTEXT,\
SSL:SSL,\
SASL_PLAINTEXT:SASL_PLAINTEXT,\
SASL_SSL:SASL_SSL,\
CONTROLLER:PLAINTEXT
# 推荐生产环境配置:
# - 内网:PLAINTEXT (仅 Broker 间通信)
# - 外网:SASL_SSL (客户端连接)
第九章:Kafka Streams 与 KSQL
9.1 Kafka Streams 基础
Kafka Streams 是构建在 Kafka 之上的轻量级流处理库:
架构特点:
┌─────────────────────────────────────────────┐
│ Kafka Streams Application │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Stream Processor │ │ State Store │ │
│ │ (拓扑执行引擎) │ │ (本地 RocksDB) │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ┌────────▼────────────────────▼─────────┐ │
│ │ Kafka Cluster │ │
│ │ Source Topic → Intermediate → Sink │ │
│ └────────────────────────────────────────┘ │
│ │
│ 特点: │
│ - 无外部依赖(不依赖 Spark/Flink 集群) │
│ - 内置容错(利用 Kafka 分区和副本) │
│ - 状态存储支持(RocksDB/内存) │
│ - Exactly-Once 语义支持 │
│ - 弹性伸缩(增加实例即可) │
└─────────────────────────────────────────────┘
9.2 流处理操作
java
// === 无状态操作 ===
// map --- 一对一转换
stream.map((key, value) -> KeyValue.pair(key, value.toUpperCase()));
// filter --- 过滤
stream.filter((key, value) -> value.length() > 10);
// flatMap --- 一对多转换
stream.flatMap((key, value) -> {
List<KeyValue<String, String>> results = new ArrayList<>();
for (String word : value.split(" ")) {
results.add(KeyValue.pair(key, word));
}
return results;
});
// === 有状态操作 ===
// groupBy + count --- 分组统计
KTable<String, Long> counts = stream
.groupBy((key, value) -> value)
.count();
// reduce --- 聚合
KTable<String, Long> sum = stream
.groupByKey()
.reduce((v1, v2) -> v1 + v2);
// join --- 连接两个流
KStream<String, String> joined = stream1.join(
stream2,
(v1, v2) -> v1 + "," + v2,
JoinWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(5))
);
// === 窗口操作 ===
// Tumbling Window (滚动窗口,不重叠)
stream.groupByKey()
.windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))
.count();
// Hopping Window (滑动窗口,可重叠)
stream.groupByKey()
.windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5))
.advanceBy(Duration.ofMinutes(1)))
.count();
9.3 KSQL 介绍
sql
-- KSQL --- 使用 SQL 语法进行流处理
-- 创建流(从 Kafka Topic)
CREATE STREAM orders_stream (
order_id VARCHAR,
user_id VARCHAR,
amount DOUBLE,
order_time BIGINT
) WITH (
KAFKA_TOPIC='orders',
VALUE_FORMAT='JSON',
TIMESTAMP='order_time'
);
-- 过滤查询
CREATE STREAM high_value_orders AS
SELECT * FROM orders_stream
WHERE amount > 1000;
-- 窗口聚合
CREATE TABLE hourly_stats AS
SELECT
user_id,
COUNT(*) AS order_count,
SUM(amount) AS total_amount,
WINDOWSTART AS window_start,
WINDOWEND AS window_end
FROM orders_stream
WINDOW TUMBLING (SIZE 1 HOUR)
GROUP BY user_id;
-- KSQL vs Kafka Streams:
-- KSQL: SQL 语法,快速原型,运维简单
-- Streams: Java API,灵活度高,性能极致
第十章:Kafka Connect 数据集成
10.1 Kafka Connect 概述
Kafka Connect 是 Kafka 的数据集成框架:
┌──────────────────────────────────────────────────────────┐
│ Kafka Connect 架构 │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Source │ │ Sink │ │
│ │ Connector │ │ Connector │ │
│ │ │ │ │ │
│ │ MySQL ────►│──── Kafka ────────►│──── ES │ │
│ │ MongoDB ──►│ │──── HDFS │ │
│ │ File ─────►│ │──── S3 │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ 运行模式: │
│ Standalone: 单进程,适合开发测试 │
│ Distributed: 多节点集群,生产环境 │
└──────────────────────────────────────────────────────────┘
10.2 常用 Connector
properties
# === JDBC Source Connector (MySQL → Kafka) ===
name=mysql-source-connector
connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
tasks.max=1
connection.url=jdbc:mysql://192.168.0.54:3306/mydb
connection.user=root
connection.password=secret
table.whitelist=users,orders
mode=timestamp+incrementing
timestamp.column.name=updated_at
incrementing.column.name=id
topic.prefix=mysql-
# === Elasticsearch Sink Connector (Kafka → ES) ===
name=elasticsearch-sink-connector
connector.class=io.confluent.connect.elasticsearch.ElasticsearchSinkConnector
tasks.max=2
topics=mysql-users
connection.url=http://192.168.0.54:9200
type.name=_doc
key.ignore=true
10.3 Debezium CDC
Debezium 是基于 Kafka Connect 的 CDC (Change Data Capture) 工具:
┌──────────────────────────────────────────────────────────┐
│ Debezium CDC 流程 │
│ │
│ ┌─────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ MySQL │────►│ Debezium │────►│ Kafka │ │
│ │ binlog │ │ Connector │ │ Topic │ │
│ └─────────┘ └──────────────┘ └──────────┘ │
│ │
│ 捕获 INSERT/UPDATE/DELETE 事件 │
│ 输出格式 (JSON): │
│ { │
│ "before": {"id": 1, "name": "Alice"}, │
│ "after": {"id": 1, "name": "Alice Updated"}, │
│ "op": "u", │
│ "ts_ms": 1717228800000 │
│ } │
└──────────────────────────────────────────────────────────┘
第十一章:Kafka 性能优化
11.1 生产者性能优化
properties
# 高吞吐 Producer 配置
batch.size=65536 # 64KB 批次
linger.ms=10 # 10ms 凑批延迟
buffer.memory=134217728 # 128MB 缓冲区
compression.type=lz4 # LZ4 压缩
acks=1 # 仅 Leader 确认(吞吐优先)
max.in.flight.requests.per.connection=5 # 5 个并发请求
11.2 消费者性能优化
properties
# 高吞吐 Consumer 配置
fetch.min.bytes=1048576 # 至少 1MB 才返回
max.poll.records=1000 # 单次拉取 1000 条
fetch.max.wait.ms=500 # 最多等 500ms
max.partition.fetch.bytes=10485760 # 单分区最多 10MB
多线程消费策略:
┌─────────────────────────────────────────────────────────┐
│ 推荐:每个线程一个 Consumer 实例 │
│ │
│ Thread 1 → Consumer 1 → poll() → process() → commit() │
│ Thread 2 → Consumer 2 → poll() → process() → commit() │
│ Thread 3 → Consumer 3 → poll() → process() → commit() │
│ │
│ 每个 Consumer 独立处理分配到的 Partition │
│ group.id 相同 → 属于同一 Consumer Group │
│ Kafka 自动分配 Partition 到 Consumer │
└─────────────────────────────────────────────────────────┘
11.3 Broker 性能优化
properties
# === JVM 调优 ===
# KAFKA_HEAP_OPTS (在 kafka-server-start.sh 或环境变量)
export KAFKA_HEAP_OPTS="-Xmx6G -Xms6G"
export KAFKA_JVM_PERFORMANCE_OPTS="-server -XX:+UseG1GC \
-XX:MaxGCPauseMillis=20 \
-XX:InitiatingHeapOccupancyPercent=35 \
-XX:+DisableExplicitGC"
# === 磁盘 IO 优化 ===
# 使用多个日志目录(多磁盘)
log.dirs=/data1/kafka,/data2/kafka,/data3/kafka
# === 网络优化 ===
num.network.threads=8 # CPU 核数
num.io.threads=16 # CPU 核数 × 2
socket.send.buffer.bytes=1048576 # 1MB 发送缓冲
socket.receive.buffer.bytes=1048576 # 1MB 接收缓冲
# === 分区数量规划 ===
# 分区总数 = Σ(每个 Topic 的分区数)
# 建议:单 Broker 分区数 < 4000(总分区)
# 单 Broker Leader 分区数 < 2000
11.4 性能基准测试
本次实战性能数据:
环境:华为云 ecs-7c2c, 2vCPU/4GiB, 4 Broker, 内网互联
Producer Benchmark (100,000 records, 256 bytes each, acks=1):
┌────────────────────┬─────────────────┐
│ 指标 │ 值 │
├────────────────────┼─────────────────┤
│ 峰值吞吐 │ 13,675 msg/s │
│ 峰值带宽 │ 3.34 MB/s │
│ P50 延迟 │ 56 ms │
│ P95 延迟 │ 49,782 ms ※ │
│ 总耗时 │ ~53 秒 │
└────────────────────┴─────────────────┘
※ 跨公网 ECS 节点间网络不稳定导致高延迟
Consumer Benchmark (50,000 records):
┌────────────────────┬─────────────────┐
│ 指标 │ 值 │
├────────────────────┼─────────────────┤
│ 消费速率 │ 4,576 msg/s │
│ 消费带宽 │ 1.12 MB/s │
│ 总耗时 │ ~11 秒 │
└────────────────────┴─────────────────┘
第十二章:Kafka 运维与故障排查
12.1 日常运维
bash
# === 每日检查清单 ===
# 1. 集群健康检查
kafka-metadata-quorum.sh --bootstrap-server localhost:9092 describe --status
# 检查: LeaderId, MaxFollowerLag (应为0或很小)
# 2. 检查未同步分区
kafka-topics.sh --bootstrap-server localhost:9092 --describe \
| grep -v "Isr:.*,.*," # ISR 数量不足的
# 3. 检查消费者积压
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group <group_name> --describe
# 4. 磁盘使用
df -h /opt/kafka/data/
du -sh /opt/kafka/data/* | sort -rh | head -10
# 5. 日志检查
tail -100 /opt/kafka/logs/server.log | grep -E "ERROR|WARN"
12.2 常见故障排查
12.2.1 Broker 启动失败
常见原因:
1. 端口被占用
→ netstat -tlnp | grep 9092
→ 或修改 listeners 端口
2. 存储格式化问题
→ 确保使用了相同的 cluster UUID
→ 重新格式化:rm -rf /opt/kafka/data && kafka-storage.sh format ...
3. Java 版本不兼容
→ Kafka 4.x 要求 Java 17+
→ java -version 确认
4. controller.quorum.voters 配置错误
→ 检查所有 Controller 节点配置一致
→ 检查 IP 和端口可达
5. 内存不足
→ 查看日志: grep OutOfMemory /opt/kafka/logs/server.log
→ 调整 KAFKA_HEAP_OPTS
实战案例 (kafka-04 启动失败):
错误: Missing required configuration "controller.listener.names"
解决: 添加 controller.listener.names=CONTROLLER
错误: No readable meta.properties files found
解决: 运行格式化命令(即使 Broker-only 节点也需要格式化)
12.2.2 消费者组重平衡问题
常见原因:
1. max.poll.interval.ms 过小 → 处理时间超过 → 被踢出
2. session.timeout.ms 过小 → 网络抖动 → 被踢出
3. Consumer 频繁重启
排查:
→ 查看 Consumer 日志中的 JoinGroup/Rebalance 事件
→ 监控 Consumer Group 的 STATE (应为 Stable)
解决:
→ 增大 max.poll.interval.ms
→ 增大 session.timeout.ms
→ 使用 cooperative-sticky 分配策略
12.2.3 消息积压问题
排查步骤:
1. 确认积压范围
kafka-consumer-groups.sh --describe
2. 判断原因:
消费速度 < 生产速度 → 扩容 Consumer
消费逻辑慢 → 优化消费代码 / 增加线程
分区数太少 → 增加分区(⚠️ 不能减少)
3. 临时方案:
增加 Consumer 实例(水平扩容)
减小 max.poll.records(加速心跳间隔)
12.3 数据一致性保障
配置清单(消息不丢失):
Producer 端:
acks=all
enable.idempotence=true
retries=MAX
max.in.flight.requests.per.connection=5
Broker 端:
default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false
Consumer 端:
enable.auto.commit=false (手动提交)
先处理消息,再提交 Offset
12.4 灾难恢复
恢复优先级:
1. 启动 Controller Quorum (至少 N/2+1 个)
2. 启动剩余 Broker
3. 检查 ISR 状态
4. 检查消费者 Offset 恢复
5. 验证数据一致性
恢复检查清单:
✓ ClusterId 正确
✓ LeaderId 已选举
✓ MaxFollowerLag = 0
✓ ISR 完整
✓ 消费者可正常消费
第十三章:Kafka 实战项目案例
13.1 日志收集系统(Filebeat + Kafka + ELK)
架构设计:
┌──────┐ ┌──────────┐ ┌────────┐ ┌────────────┐ ┌──────────┐
│ Apps │───►│ Filebeat │───►│ Kafka │───►│ Logstash │───►│ ES/Kibana│
│ │ │ (采集) │ │ (缓冲) │ │ (解析过滤) │ │ (存储展示)│
└──────┘ └──────────┘ └────────┘ └────────────┘ └──────────┘
优势:
- Kafka 作为缓冲层,解耦采集和处理
- Logstash 宕机不影响日志采集(Kafka 持久化)
- 支持多个 Consumer Group(实时处理 + 离线归档)
13.2 实时数据管道(MySQL CDC)
MySQL → Debezium → Kafka → Stream Processing → Sink
┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ ┌──────┐
│ MySQL │──►│ Debezium │──►│ Kafka │──►│ Flink/ │──►│ HDFS │
│ (binlog)│ │ Connector│ │ │ │ Streams │ │ S3 │
└─────────┘ └──────────┘ └────────┘ └──────────┘ └──────┘
数据流转:
1. Debezium 捕获 MySQL binlog 变更
2. 写入 Kafka Topic (每表一个 Topic)
3. 流处理:清洗、转换、聚合
4. Sink Connector 写入目标存储
13.3 微服务事件驱动架构
基于 Kafka 的 Event-Driven 微服务:
┌──────────┐ Event ┌────────┐ Event ┌──────────┐
│ 订单服务 │────────►│ Kafka │────────►│ 库存服务 │
│ │ order │ │ order │ │
└──────────┘ created └────────┘ created └──────────┘
│
│ Event: ┌──────────┐
│ order │ 通知服务 │
│ created │ (短信/邮件)│
└──────────►│ │
└──────────┘
事件设计原则:
- 事件不可变(Immutable)
- 事件包含完整上下文(避免额外查询)
- 使用 Correlation ID 追踪链路
- 设计死信队列(DLQ)处理失败事件
第十四章:Kafka 新特性与未来
14.1 Kafka 4.x 新特性
14.1.1 KRaft 模式成为唯一选项
Kafka 4.x 完全移除 ZooKeeper 相关代码:
变化:
- 无 zookeeper.connect 配置
- 无 ZK 依赖的启动脚本
- 元数据 `@metadata` Topic 替代 ZK 存储
- kafka-storage.sh format 替代 ZK 初始化
好处:
✓ 启动速度提升 10x+ (无需等待 ZK 连接)
✓ 元数据操作延迟降低 10-100x
✓ 支持百万级分区
✓ 运维复杂度大幅降低
14.1.2 Tiered Storage(分层存储)
将冷数据自动迁移到廉价对象存储:
┌─────────────┐ ┌──────────────────┐
│ Local Disk │───►│ S3 / HDFS / OSS │
│ (热数据) │ │ (冷数据) │
│ 最近 N 天 │ │ 长期保留 │
└─────────────┘ └──────────────────┘
优势:
- 本地磁盘只保留热数据
- 对象存储保留全量历史
- 消费者可透明访问冷数据
- 降低存储成本 50-80%
14.1.3 Docker 容器化部署
yaml
# docker-compose.yml for Kafka 4.3.0
version: '3.8'
services:
kafka:
image: apache/kafka:4.3.0
ports:
- "9092:9092"
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_LOG_DIRS: /var/lib/kafka/data
volumes:
- kafka-data:/var/lib/kafka/data
volumes:
kafka-data:
14.2 云原生 Kafka
| 服务 | 提供商 | 特点 |
|---|---|---|
| Confluent Cloud | Confluent | 官方商业版,全托管,K8s 原生 |
| AWS MSK | Amazon | AWS 托管,与 AWS 生态集成 |
| Azure Event Hubs | Microsoft | 兼容 Kafka 协议 |
| 阿里云消息队列 Kafka | 阿里云 | 国内首选,多 Region 部署 |
| 华为云 DMS Kafka | 华为云 | 与华为云 ECS/CCE 集成 |
第十五章:Kafka 面试与进阶
15.1 面试高频问题
15.1.1 基础概念类
Q1: Kafka 为什么快?
- 顺序写入磁盘(追加写)
- 零拷贝技术(sendfile)
- Page Cache 利用
- 批量压缩发送
- 分区并行处理
Q2: Kafka 如何保证消息不丢失?
- Producer: acks=all + 幂等性
- Broker: RF=3 + min.insync.replicas=2 + unclean.leader.election.enable=false
- Consumer: 手动提交 Offset + 先处理后提交
Q3: Kafka 如何保证消息顺序?
- 分区内有序:相同 Key 路由到同一 Partition
- 全局有序:单分区 Topic(牺牲吞吐)
- 幂等生产者:max.in.flight.requests.per.connection ≤ 5
15.1.2 原理机制类
Q4: ISR 是什么?什么情况下副本会从 ISR 中移除?
- ISR = 与 Leader 保持同步的副本集合
- 移除条件:超过 replica.lag.time.max.ms (30s) 未同步
Q5: HW 和 LEO 分别是什么?
- LEO: 副本下一条待写入消息的 Offset
- HW: 所有 ISR 副本都已确认的最高 Offset(消费者可见的边界)
Q6: Controller 的职责?
- 分区管理、Leader 选举、Broker 上下线处理、元数据维护
15.1.3 实战应用类
Q7: 消费者组重平衡的触发条件?
- 消费者加入/离开
- Topic 分区数变化
- 消费者处理超时 (max.poll.interval.ms)
Q8: 如何处理消息积压?
- 临时:增加 Consumer 实例
- 长期:增加分区数、优化消费逻辑
- 监控:RecordsLag 指标
Q9: Kafka 为什么使用 Pull 模式?
- Consumer 可控制消费速度
- 避免 Push 导致的 Consumer 过载
- 支持批量拉取,提高吞吐
15.2 深度学习资源
| 资源 | 说明 |
|---|---|
| 《Kafka 权威指南(第2版)》 | 必读经典,覆盖原理+实战 |
| Apache Kafka 官方文档 | 最权威的配置参考 |
| Confluent 博客 | 最佳实践和新技术介绍 |
| Kafka 源码 | github.com/apache/kafka |
| Kafka Summit 演讲 | 业界实践分享 |
15.3 学习路线图
初级(入门)→ 中级(实战)→ 高级(原理)→ 专家(架构)
初级:
✓ 理解消息队列概念
✓ 掌握 Kafka 核心概念(Topic/Partition/Broker/Offset)
✓ 能使用 CLI 工具操作 Kafka
✓ 能编写 Producer/Consumer 代码
中级:
✓ 理解副本机制、ISR、HW/LEO
✓ 能搭建和运维 Kafka 集群
✓ 掌握性能调优技巧
✓ 能处理常见故障
高级:
✓ 深入理解存储引擎、零拷贝、Page Cache
✓ 掌握 Kafka Streams/KSQL
✓ 能设计事件驱动架构
✓ 能进行集群容量规划
专家:
✓ 阅读和理解 Kafka 源码
✓ 能二次开发 Kafka 插件
✓ 能设计跨数据中心方案
✓ 能培训团队和推动 Kafka 落地
附录
附录 A:Kafka 常用命令速查
bash
# ===== Topic 管理 =====
# 创建 Topic
kafka-topics.sh --bootstrap-server <host>:9092 --create \
--topic <name> --partitions <N> --replication-factor <N>
# 列出 Topic
kafka-topics.sh --bootstrap-server <host>:9092 --list
# 查看 Topic 详情
kafka-topics.sh --bootstrap-server <host>:9092 --describe --topic <name>
# 增加分区
kafka-topics.sh --bootstrap-server <host>:9092 --alter \
--topic <name> --partitions <N>
# 删除 Topic
kafka-topics.sh --bootstrap-server <host>:9092 --delete --topic <name>
# ===== 生产消费 =====
# 控制台生产者
kafka-console-producer.sh --bootstrap-server <host>:9092 --topic <name>
# 控制台消费者
kafka-console-consumer.sh --bootstrap-server <host>:9092 \
--topic <name> --from-beginning
# ===== Consumer Group =====
# 列出所有 Group
kafka-consumer-groups.sh --bootstrap-server <host>:9092 --list
# 查看 Group 消费状态
kafka-consumer-groups.sh --bootstrap-server <host>:9092 \
--group <name> --describe
# 重置 Offset
kafka-consumer-groups.sh --bootstrap-server <host>:9092 \
--group <name> --topic <topic> --reset-offsets --to-earliest --execute
# ===== 集群管理 =====
# 查看 KRaft 状态
kafka-metadata-quorum.sh --bootstrap-server <host>:9092 \
describe --status
# 查看 Broker 信息
kafka-broker-api-versions.sh --bootstrap-server <host>:9092
# ===== 性能测试 =====
# Producer 性能测试
kafka-producer-perf-test.sh --topic <name> \
--num-records 100000 --record-size 256 --throughput -1 \
--producer-props bootstrap.servers=<host>:9092 acks=1
# Consumer 性能测试
kafka-consumer-perf-test.sh --bootstrap-server <host>:9092 \
--topic <name> --messages 50000
附录 B:配置参数详解
Producer 核心参数
| 参数 | 默认值 | 说明 |
|---|---|---|
bootstrap.servers |
--- | Broker 地址列表 |
key.serializer |
--- | Key 序列化器(全类名) |
value.serializer |
--- | Value 序列化器(全类名) |
acks |
1 | 确认机制(0/1/all) |
retries |
MAX | 重试次数 |
batch.size |
16384 | 批次大小(字节) |
linger.ms |
0 | 延迟发送(毫秒) |
buffer.memory |
32MB | 缓冲区大小 |
compression.type |
none | 压缩算法(gzip/snappy/lz4/zstd) |
max.request.size |
1MB | 请求最大大小 |
enable.idempotence |
true | 幂等性(Kafka 3.x+ 默认开启) |
max.in.flight.requests.per.connection |
5 | 并发请求数 |
Consumer 核心参数
| 参数 | 默认值 | 说明 |
|---|---|---|
bootstrap.servers |
--- | Broker 地址列表 |
group.id |
--- | 消费者组 ID |
auto.offset.reset |
latest | 初始 Offset 策略(earliest/latest/none) |
enable.auto.commit |
true | 是否自动提交 Offset |
auto.commit.interval.ms |
5000 | 自动提交间隔 |
max.poll.records |
500 | 单次拉取最大记录数 |
max.poll.interval.ms |
300000 | 两次 poll 最大间隔 |
session.timeout.ms |
45000 | 会话超时 |
heartbeat.interval.ms |
3000 | 心跳间隔 |
fetch.min.bytes |
1 | 最小拉取字节 |
fetch.max.wait.ms |
500 | 最大等待时间 |
max.partition.fetch.bytes |
1MB | 单分区最大拉取字节 |
Broker 核心参数
| 参数 | 默认值 | 说明 |
|---|---|---|
process.roles |
--- | KRaft 角色(broker/controller) |
node.id |
--- | Broker 唯一 ID |
controller.quorum.voters |
--- | Controller 仲裁节点 |
listeners |
PLAINTEXT://:9092 | 监听地址 |
advertised.listeners |
--- | 对外公布的地址 |
log.dirs |
/tmp/kafka-logs | 日志存储目录 |
num.partitions |
1 | 新建 Topic 默认分区数 |
default.replication.factor |
1 | 默认副本因子 |
min.insync.replicas |
1 | 最小 ISR 数 |
log.retention.hours |
168 | 日志保留时间(小时) |
log.segment.bytes |
1GB | 日志段大小 |
offsets.topic.replication.factor |
1 | Offset Topic 副本因子 |
unclean.leader.election.enable |
false | 是否允许非 ISR 副本当选 Leader |
附录 C:性能测试工具使用
bash
# === Producer 性能测试 ===
# 参数说明:
# --num-records: 总消息数
# --record-size: 每条消息字节数
# --throughput: 限速(-1 表示不限速)
# --producer-props: Producer 配置
# 基础吞吐测试
kafka-producer-perf-test.sh \
--topic test-perf \
--num-records 1000000 \
--record-size 100 \
--throughput -1 \
--producer-props bootstrap.servers=localhost:9092 acks=1
# === Consumer 性能测试 ===
kafka-consumer-perf-test.sh \
--bootstrap-server localhost:9092 \
--topic test-perf \
--messages 1000000
# === 端到端延迟测试 ===
# 使用 kafka-verifiable-producer/consumer
kafka-verifiable-producer.sh --bootstrap-server localhost:9092 \
--topic test-latency --max-messages 10000
附录 D:常见问题 FAQ
Q: 分区数可以减少吗?
A: 不能。只能增加不能减少。如需减少,需要删除重建 Topic。
Q: acks=all 时为什么还会丢消息?
A: 检查 min.insync.replicas 配置。如果 ISR 数 < min.insync.replicas,写入会失败(NotEnoughReplicas)。
Q: Kafka 适合作为任务队列吗?
A: 可以,但不如 RabbitMQ 方便。需要自行实现重试、延迟、死信等机制。
RocketMQ 对任务队列场景更友好。
Q: Consumer Group 中的消费者数量可以超过分区数吗?
A: 可以,但多出的消费者会空闲。Kafka 保证一个 Partition 只分配给 Group 内一个 Consumer。
Q: KRaft 模式需要几个 Controller 节点?
A: 生产环境建议 3 个。3 节点可容忍 1 台故障,5 节点可容忍 2 台。必须为奇数。
Q: Kafka 消息默认保留多久?
A: 默认 7 天 (log.retention.hours=168)。可调整为更短(小时级)或更长(月级)。
Q: 如何查看某条特定 Offset 的消息?
A: 使用 kafka-console-consumer.sh 的 --offset 参数,或使用编程方式 seek() 到指定 offset。
附录 E:学习路线图
Kafka 学习路径(建议 8 周):
Week 1-2:基础入门
□ 理解消息队列概念与 Kafka 定位
□ 掌握核心概念(Topic/Partition/Broker/Producer/Consumer)
□ 单机安装 Kafka,使用 CLI 工具
□ 阅读《Kafka 权威指南》第 1-3 章
Week 3-4:集群与 API
□ 搭建多节点 KRaft 集群
□ 编写 Producer/Consumer Java 代码
□ 理解 acks、重试、幂等性
□ 掌握 Offset 管理、Consumer Group
Week 5-6:内部机制
□ 理解日志存储结构(Segment/Index)
□ 深入副本机制(Leader/Follower/ISR/HW/LEO)
□ 掌握 Controller 选举与 KRaft 共识
□ 了解零拷贝、Page Cache 优化
Week 7-8:高级主题与实战
□ Kafka Streams / KSQL 流处理
□ Kafka Connect 数据集成
□ 性能调优与监控
□ 实战项目(日志收集/CDC/事件驱动)
□ 安全配置(SSL/SASL/ACL)
附录 F:最佳实践总结
Topic 设计:
✓ 使用有意义的命名(如 domain.entity.event)
✓ 合理设置分区数(根据吞吐预估)
✓ 生产环境 replication.factor ≥ 3
✓ 关键 Topic 设置 min.insync.replicas ≥ 2
✓ 使用合适的清理策略(delete vs compact)
Producer:
✓ 关键数据使用 acks=all
✓ 启用幂等性(enable.idempotence=true)
✓ 选择合适的压缩算法(lz4 推荐)
✓ 设置合理的 batch.size 和 linger.ms
✓ 始终处理 send() 的回调异常
Consumer:
✓ 使用手动提交 Offset(enable.auto.commit=false)
✓ 先处理消息,再提交 Offset
✓ 设置合理的 max.poll.records 和 max.poll.interval.ms
✓ 使用 CooperativeStickyAssignor 减少重平衡
✓ 监控 RecordsLag,及时处理积压
Broker:
✓ 使用独立磁盘存储日志
✓ Controller 节点配置 3 个(奇数)
✓ 设置合理的 JVM 堆大小(不超过 6GB)
✓ 监控关键指标(UnderReplicatedPartitions、ActiveControllerCount)
✓ 配置日志轮转和清理策略
安全:
✓ 公网访问必须使用 SSL/SASL
✓ 最小权限原则配置 ACL
✓ 内网通信使用 PLAINTEXT(性能最好)
✓ 启用审计日志
运维:
✓ 每日检查集群健康状态
✓ 监控消费者 Lag
✓ 定期备份关键数据
✓ 制定扩容/缩容方案
✓ 配置告警规则(ISR 不足、节点宕机、Lag 过高)
文档信息
实战集群:华为云 ecs-7c2c x 4 | Ubuntu 24.04 | Kafka 4.3.0 | KRaft
集群 UUID:1S9ggrMYQaCHBqfZy8hhOg
完成时间:2026-06-01
总字数:~25,000 字 | 代码示例:40+ | 图表:20+