Kafka 大规模摄取与处理 | Rajamohan Jabbala
发布: (2026年1月7日 GMT+8 16:04)
5 min read
原文: Dev.to
Source: Dev.to

大多数 Kafka 故障并不是因为 Kafka 无法扩展。
它们发生是因为团队从未做过数学计算。
“良好” 的样子(先看 SLO)
一个生产环境的 Kafka 流水线应该:
- 以低延迟处理每个主题的 N 条消息/秒
- 通过分区、消费者、Broker 实现线性扩展
- 保证至少一次(或恰好一次)语义
- 通过消费者组支持 fan‑out
- 在明确的延迟、吞吐量、持久性 SLO 范围内运行
示例 SLO
- 生产延迟 p99 ≤ X ms
- 消费者延迟 ≤ Y 秒(稳态)
- 在 2 倍峰值后恢复 ≤ Z 分钟
- 可用性 ≥ 99.9 %
如果你不定义这些,Kafka 调优就会沦为迷信。
Kafka 机制(真正重要的部分)
- 主题通过 分区 扩展。
- 一个分区 → 每个消费者组只能有一个消费者。
- 多个消费者组 = 独立的重新读取(fan‑out)。
规则:
一个消费者组中有用的最大消费者数 = 分区数。
添加超过分区数的消费者 不会 提高吞吐量。
逻辑架构
Producers → orders topic (P partitions, RF=3)
Kafka cluster distributes:
• One leader per partition
• Replicas across brokers
Downstream consumer groups:
• Fraud consumer group
• Analytics consumer group
• ML feature consumer group
Each group owns its own offsets and scales independently.
容量规划(不可或缺的步骤)
输入
| 符号 | 含义 |
|---|---|
| T | 消息/秒 |
| S | 平均消息大小(字节,已压缩) |
| R | 副本因子 |
| C | 每个消费者的消息/秒(测得) |
| H | 预留空间(1.3–2×) |
| RetentionDays | 保留天数 |
核心公式
- 分区数:
P = ceil((T / C) × H) - 入口流量:
Ingress = T × S × R - 出口流量(每个组):
Egress = T × S - 每日存储(仅 leader):
T × S × 86,400
再乘以R和保留天数即为总存储。
示例(1 M 条消息/秒)
| 参数 | 值 |
|---|---|
| T(消息/秒) | 1,000,000 |
| S(字节) | 200 |
| C(消息/秒/消费者) | 25,000 |
| H(预留空间) | 1.5 |
| RF(副本因子) | 3 |
结果
- 分区数:60
- 入口流量:约 572 MB/秒
- 每个消费者组的出口流量:约 191 MB/秒
- 3 天保留(含副本)的存储:约 155 TB
这就是为什么“直接加 broker”不是可行的策略。
不会适得其反的分区策略
- 使用高基数键(例如
order_id,而不是country)。 - 积极监控倾斜。
- 早期稍微超分区,以免后期重新分片成本高昂。
消费者组扩展
- 将消费者扩展到分区数 (
P) 的上限。 - 为不同的流水线使用独立的消费者组。
- 基于延迟增长 自动扩容,而不是基于原始延迟值。
可行的可靠性默认配置
acks=all
min.insync.replicas=2 # 当 RF=3 时
enable.idempotence=true
unclean.leader.election.enable=false
# Rack/AZ 感知的副本放置
- 仅在业务语义需要时才使用恰好一次语义。
可观测性 > 调优
监控
- 每个分区的延迟增长
- p95/p99 生产和消费延迟
- 未复制完整的分区
- 磁盘、网卡、控制器健康状况
扩容
- 消费者 → 当延迟上升时
- 分区 → 当消费者饱和时
- Broker → 当磁盘/网卡压力增大时
最后总结
Kafka 并不是因为它是 Kafka 才不扩展。
它之所以能扩展,是因为你把它设计成可扩展的。
- 数学胜过希望。
- 测量击败神话。