一、Kafka 发送消息的 核心架构设计
flowchart LR
Producer -->|1.选择分区| Broker
Broker -->|2.写入Leader分区| Partition[(Partition)]
Partition -->|3.同步副本| Follower1 & Follower2
Broker -->|4.持久化| CommitLog[(顺序写磁盘)]
Consumer -->|5.拉取消息| Broker
1. 生产者发送流程
- 分区路由:根据
hash(key)%分区数或轮询策略选择目标分区 - 批处理缓冲:内存中的
RecordAccumulator缓存消息,批次达到batch.size(默认16KB)或linger.ms(默认0ms)触发发送 - 网络传输:使用NIO的
Selector实现非阻塞IO,通过Sender线程异步发送
2. Broker存储设计
- 日志分段:每个分区划分为多个
LogSegment(默认1GB),包含.log数据文件+.index索引文件 - 页缓存优化:利用Linux页缓存(Page Cache)避免JVM堆内存GC影响
- 零拷贝传输:消费者读取时通过
sendfile系统调用直读磁盘文件
二、Kafka 为什么快?
❶ 吞吐量优化设计
pie
title 性能优化因素占比
"顺序磁盘IO" : 40
"零拷贝技术" : 25
"批量处理" : 20
"压缩算法" : 15
关键技术解析:
- 顺序写盘:消息以追加(Append)方式写入,机械磁盘吞吐可达600MB/s
- 零拷贝:消费者读取时数据不经过用户空间,直接从内核缓冲区传输到网卡
- 压缩算法:支持Snappy/Gzip/LZ4,降低网络传输量(如LZ4压缩率约50%)
- 内存映射:通过
MappedByteBuffer将磁盘文件映射到内存地址空间
❷ 精准一次(Exactly-Once)实现
sequenceDiagram
participant P as Producer
participant B as Broker
P->>B: 发送消息 (PID=100, Sequence=5)
B->>B: 检查Sequence连续性
alt 新PID或Sequence连续
B-->>P: ACK
else 重复Sequence
B-->>P: 丢弃消息
end
实现机制:
-
幂等生产者:
props.put("enable.idempotence", "true"); // 启用幂等性每个生产者实例分配唯一
PID,每条消息携带单调递增Sequence Number,Broker端缓存最近5个分区的序列号进行去重 -
事务支持:
producer.beginTransaction(); producer.send(record1); producer.send(record2); producer.commitTransaction(); // 提交跨分区原子写使用事务协调器(Transaction Coordinator)管理两阶段提交(2PC)
三、Kafka 高可用副本机制
❶ 副本分布策略
graph TD
TopicA-P0 -->|Leader| Broker1
TopicA-P0 -->|Follower| Broker2
TopicA-P0 -->|Follower| Broker3
TopicA-P1 -->|Leader| Broker2
TopicA-P1 -->|Follower| Broker3
TopicA-P1 -->|Follower| Broker1
核心规则:
- 每个分区的副本分布在不同的Broker(由
broker.rack感知机架分布) - Leader处理所有读写请求,Follower异步/同步拉取数据
- ISR(In-Sync Replicas)列表维护与Leader同步的副本
❷ 副本同步过程
sequenceDiagram
participant Leader
participant Follower
Leader->>Follower: 发送消息批次 (lastOffset=100)
Follower->>Leader: 响应成功 (fetchOffset=100)
Leader->>Leader: 更新HW(High Watermark)=100
Follower->>Follower: 提交消息到本地Log
关键参数:
replica.lag.time.max.ms(默认30s):Follower未同步则移出ISRmin.insync.replicas(默认1):最小ISR副本数,影响写入可用性
❸ 故障恢复机制
sequenceDiagram
participant C as Controller
participant B1 as Broker1(Leader)
participant B2 as Broker2(Follower)
B1--x B1: 宕机
C->>C: 检测Leader失效
C->>B2: 提升为新Leader
B2->>B2: 更新ZooKeeper元数据
C->>All Brokers: 广播Leader变更
关键过程:
- Controller(通过ZooKeeper选举)监控Broker存活状态
- 从ISR中选择新的Leader(优先选择存活副本)
- 若ISR为空且
unclean.leader.election.enable=true,允许非同步副本成为Leader
四、Kafka 优势总结
核心优势对比表
| 维度 | Kafka实现方案 | 传统MQ(如RabbitMQ) |
|---|---|---|
| 吞吐量 | 单机百万级TPS(开启压缩/批处理) | 万级TPS |
| 消息持久化 | 磁盘存储支持TB级数据保留 | 内存存储为主 |
| 水平扩展 | 分区可动态增加,支持千级分区 | 队列扩展困难 |
| 数据一致性 | 通过ISR+HW机制保证副本一致性 | 主从异步复制存在数据丢失风险 |
典型性能数据(单Broker测试)
xychart-beta
title 吞吐量对比(消息大小1KB)
x-axis ["Kafka", "RabbitMQ", "RocketMQ"]
y-axis "TPS (万)" 0 --> 100
bar [78, 12, 45]
line [78, 12, 45]
五、Kafka的 最佳实践建议
-
分区规划:
- 目标吞吐量 = 单分区吞吐 * 分区数
- 单分区极限:约10MB/s(未压缩)或 50MB/s(启用压缩)
-
可靠性配置:
acks=all // 等待所有ISR副本确认 min.insync.replicas=2 // 最小同步副本数 replication.factor=3 // 副本数 -
监控指标:
- Under Replicated Partitions(URP)应接近0
- Leader选举次数(unclean选举需告警)
Kafka的"快"来源于体系化设计,而可靠性则建立在严密的副本同步机制上。这种速度与可靠性的平衡,使其成为现代数据管道的核心基础设施。