先说说我为什么想写这篇。做数据管道做了六七年,Kafka 几乎是我每天都要打交道的组件。早年间在业务系统里用 Kafka 做异步解耦,后来转到大数据平台侧,从 Flink 实时计算到 ClickHouse 数仓同步,消息中间件里七成以上的流量都跑在 Kafka 上。这个过程中有一个东西躲不开、绕不过,而且踩坑几乎都和它有关——就是消息分区机制。
很多人学 Kafka,搞懂了 Producer、Consumer、Broker、Topic 这些概念,就觉得入门了。但真到了生产环境,遇到消费积压、消息乱序、分区倾斜、Rebalance 抖动这些问题时,才会发现自己对分区机制的理解还停留在"数据分片存储"这个表面结论上。这篇文章我主要就把分区机制这件事讲透:它为什么存在、生产端怎么选分区、消费端怎么分配分区、以及在大数据场景下如何围绕分区做容量规划和排障。内容不追求教科书式的全量覆盖,而是把日常干活真正用得上的部分说清楚。
1. 分区机制的设计初衷:Kafka 为什么非分区不可
很多朋友刚接触 Kafka 时都会有这么个困惑:我用 RabbitMQ 不是挺好吗?队列又不是不能扩展,为什么 Kafka 要搞出"分区"这么个中间层?要回答这个问题,得先明白 Kafka 面对的场景和传统消息队列有本质区别。
传统消息队列核心解决的是"点对点"和"发布订阅"模式下的异步通信,消息堆积量级一般在每秒几千到几万条。而 Kafka 从诞生第一天就是为日志聚合、行为追踪、Metrics 采集这类海量数据设计的——单 Topic 每秒百万条消息是常态,而且要求数据保留几天甚至几十天,供多个下游消费。这种场景下,如果整个 Topic 只有一个写入入口、一份存储文件,那么无论怎么优化单机性能,都会有天花板。
1.1 一个普遍被忽略的前提:Topic 是逻辑概念,分区是物理概念
这是理解整个分区机制的第一块基石。Topic 是你在业务层面看到的逻辑名称,比如 ods_user_login_log、dwd_order_detail。但本质上,Kafka 并不在 Topic 级别管理消息的存储和读写。真正干活的是 Topic 下面的分区(Partition)。
分区是怎么工作的?我打个比方。Topic 相当于一个大型物流仓库的收货台账,而分区就是仓库里划分出来的一个个货架区。业务方只负责把货物运到仓库门口——也就是发送消息到 Topic,但货物具体上哪个货架,是由分区策略决定的。每个货架有自己独立的入库单(Segment 文件)、独立的出库记录(Consumer Offset),货物只能按顺序摆在自己所在的货架内。
这个设计带来的直接收益是并行度的提升。Producer 可以同时往多个分区写,Consumer 可以同时从多个分区读。分区之间互不干扰,单分区内部天然有序。这是 Kafka 能做到高吞吐的根本原因。
1.2 分区、副本与 Broker:三者的关系才是水平扩展的根基
还有一个容易混淆的地方:分区和副本是绑在一起的,但职责完全不同。分区负责"数据分片切割"和"并行承载",副本负责"数据冗余备份"。一个 Topic 设定 12 个分区、3 个副本,就意味着总共有 36 份分区数据,其中 12 份是 Leader 分区,24 份是 Follower 副本。Leader 分区负责读写流量,Follower 副本只做数据同步,一旦 Leader 所在的 Broker 宕机,会从 ISR 集合里选出一个新的 Leader 继续干活。
在集群扩容时,分区会相对均衡地散落到各台 Broker 上。比如集群原本 3 台 Broker,Topic 有 12 个分区,那么理想状态下每台 Broker 承担 4 个 Leader 分区。扩容到 6 台后,如果不做任何操作,新加入的 Broker 默认不会自动分到分区——你需要手动执行分区重分配,或者依赖 Cruise Control 这类工具来自动平衡。这也是很多团队集群扩容后反而出现单台 Broker 流量打满的原因:分区没跟着扩。
所以,Kafka 的高可用和高吞吐,靠的是分区把单个 Topic 的数据切开,再把切好的"数据块"分布到多台机器上。理解了"分区数 =
