分区数选择
分区数是一个"选了就很难改"的决策。太少限制并行度,太多增加运维成本。本文给出选型依据和扩展风险。
1. 分区数决定了什么
| 维度 | 分区数的影响 |
|---|---|
| 消费并行度 | 分区数 = 消费并行度的天花板 |
| 生产并行度 | 多分区可以并行写入不同 Broker |
| 故障恢复开销 | Broker 故障时需为大量分区重新选举 Leader,分区副本越多控制面开销越大 |
| Controller 压力 | 元数据管理开销随分区数增长 |
| 文件句柄 | 每个分区对应多个文件 |
2. 选型依据
并发数只是分区数的下限之一,不能单独决定分区数。分区数由三个维度共同约束,取其中最大值:
分区数 ≥ max(写入所需分区数, 消费所需分区数, 消费者并行数)- 写入容量:目标写入吞吐 ÷ 单分区可持续写入能力。单分区写入能力受消息大小、复制因子、acks 配置影响,不是固定常量。
- 消费容量:目标消费吞吐 ÷ 单分区可持续消费能力,保证分区总数足以承载消费吞吐。
- 消费并行度:需要同时工作的消费者数量,机制见 分区与 Offset。
消费容量回答「分区能不能装下吞吐」,消费并行度回答「能不能让足够多的消费者同时干活」。两者不等价:多挂一个消费者不必然提高吞吐,还要看分区分配、单分区处理能力和下游瓶颈。
三个维度都满足后,最终配置还要结合 Broker 资源上限和实测结果校验。
以 KB 级消息、复制因子 3 的典型业务为例,分区数的经验数量级大致是:低吞吐 3~6、中等吞吐 10~30、高吞吐 50~100。这些数字随消息大小和复制因子变化很大,仅用于判断当前分区是否明显偏多或偏少,不能当作容量公式。
3. 分区过多的代价
分区数量与分区副本总数是两个概念,实际开销取决于副本总数。以下按资源类型区分:
| 代价 | 说明 |
|---|---|
| 文件句柄多 | 每个分区副本对应多个文件(.log, .index, .timeindex) |
| 内存占用增加 | 每个分区副本的索引和缓冲区消耗内存 |
| 复制流量增加 | 副本总数增加通常会增加副本维护开销和潜在复制负载,实际流量取决于写入速率、消息大小与 ISR 状态 |
故障恢复要区分两个阶段:单个分区的 Leader 选举开销很小;Broker 故障会同时触发大量分区重新选举、元数据更新和副本恢复,恢复时间取决于受影响的分区副本数量与控制面、数据面负载,不存在统一的固定阈值。排查见 Broker 故障。
如果分区副本总数过大导致恢复变慢,先检查是否分区过量、副本数是否需要收敛,而不是简单追加分区。
4. 分区扩展
分区数只能增加、不能减少。
kafka-topics.sh --alter --topic my-topic --partitions 12 --bootstrap-server localhost:9092扩展风险
| 风险 | 说明 |
|---|---|
| Key 路由变化 | 默认哈希分区逻辑下,新增分区改变取模结果,同一 Key 的新消息可能进入不同分区,跨分区无序 |
| 消费者 Rebalance | 分区数变化触发 Rebalance |
| 数据倾斜 | 新分区没有历史数据,短期内数据不均衡 |
带 Key 的消息在默认哈希分区逻辑下,按序列化后的 Key 与当前分区数取模决定目标分区;无 Key 的消息走粘性分区,不受取模变化影响。扩容不会迁移历史消息,旧消息留在原分区,同一业务实体的新旧消息因此可能分散到不同分区,即使单分区内部有序,跨分区也没有顺序保证。使用自定义分区器或稳定分片映射时不适用上述结论。
扩展前的检查清单
- 该 Topic 是否依赖 Key 的顺序性?如果是,扩展分区会破坏顺序
- 消费者组中有多少个消费者?扩展后是否需要增加消费者
- 是否在低峰期执行?扩展会触发 Rebalance,影响消费
- 扩容前先确认瓶颈在分区并行度而非消费者处理速度,判断方法见 消费者 Lag 过大
5. 分区数 vs 消费者数
同一消费者组内,一个分区同一时刻至多分配给一个消费者,但消费者与分区不必一一对应。
消费者数 < 分区数:每个消费者负责多个分区
消费者数 > 分区数:多余的消费者空闲,不参与消费消费者数量由处理能力、分区分配和故障恢复时间要求共同决定,不等于「分区数减一」。需要故障后快速恢复时,应通过实例部署和消费组协调设计冗余,而不是多挂一个消费者当热备——同一组内新增消费者会直接参与分区分配,不会自动处于待命状态。