外观
Kafka 分区怎么设计
难度与前置
难度:入门
前置:知道消息按 key 哈希到分区;消费并行上限 ≈ 分区数。
读完能做什么:按吞吐、顺序、热点三维给 Topic 定分区键与分区数,并写清扩容与验收标准。
适用场景
当你要新建业务 Topic或改造「单分区撑不住 / 热点分区打满」的旧主题时,用本篇定分区策略。
不适用:
- 临时调试 Topic(单分区即可)
- 已有强顺序契约且改键会破坏下游(先评迁移方案)
- 吞吐极低、无 SLA 压力的内部流水
真实场景(一条)
投放事件 Topic 最初 3 分区,Flink 并行度 3。大促时入站 QPS×5,总 lag 高且 partition 1 占据 70% 流量(大客户 channel_id 哈希撞车)。扩消费者到 12 无效(受 3 分区限制)。
改法:评估顺序需求后改为 24 分区;分区键改为更均匀业务键或加盐;大客户单独 Topic。扩容后峰值可水平扩展,单分区字节占比回落到健康区间。
怎么做(步骤清单)
1. 先写三条约束
| 约束 | 问题 | 例子 |
|---|---|---|
| 顺序 | 是否要同 key 严格有序? | 同 user_id 的状态变更要有序 |
| 吞吐 | 峰值消息/字节与目标延迟 | 峰值 5 万条/s,延迟 < 30s |
| 热点 | 是否存在超级 key? | 头部渠道占总流量 40% |
三者冲突时的默认优先级:业务正确的顺序 > 可解释的热点隔离 > 分区数凑吞吐。
2. 分区键怎么选
| 键策略 | 顺序保证 | 风险 | 适用 |
|---|---|---|---|
| 无 key(轮询) | 无 | 无顺序 | 日志采集、可乱序指标 |
user_id / device_id | 同用户有序 | 头部用户热点 | 用户行为流 |
order_id | 同订单有序 | 一般较均匀 | 订单事件 |
channel_id | 同渠道有序 | 大渠道热点 | 需渠道内有序时 |
hash(key)+salt | 破坏原顺序 | 要二次聚合 | 强热点打散 |
TIP
需要有序时:分区键 = 有序粒度;消费者端同分区单线程处理。
不需要有序时:宁可无 key 或加盐,也不要死守会热点的粗键。
3. 分区数估算
text
分区数 ≥ max(
峰值吞吐 / 单分区舒适吞吐,
计划消费者最大并行度,
未来 6~12 个月增长预留 ×1.5~2
)常见起步:中小主题 6~12;主力实时明细 24~64;避免一上来上千分区。
4. 副本与其它 Topic 级参数
bash
kafka-topics.sh --bootstrap-server ${brokers} --create \
--topic ods_ad_spend_event \
--partitions 24 \
--replication-factor 3 \
--config min.insync.replicas=2 \
--config retention.ms=172800000 \
--config compression.type=lz4| 参数 | 建议 |
|---|---|
replication-factor | 生产 ≥ 3 |
min.insync.replicas | 2(配合 producer acks=all) |
| 保留时长 | 覆盖补数窗口(如 2~7 天) |
| 压缩 | lz4/zstd 按生态统一 |
5. 扩分区注意点
- 只能增不能减(常规)
- 旧消息仍在旧分区;新 key 映射会变,同 key 跨扩容前后可能落到不同分区 → 跨边界顺序不保证
- 扩容后同步调 Flink/消费者并行,并观察再均衡
- 大改键:优先新 Topic + 双写/迁移,而不是原地赌命
6. 与消费者并行度对齐
text
有效消费并行 ≈ min(应用并行度, 分区数)Flink:source 并行度不要长期小于热点治理后的需求,也不要无脑大于分区数。
7. 设计评审检查单
- [ ] 有序粒度与分区键一致,并写进契约
- [ ] 热点 key 有数据分布抽样
- [ ] 分区数 ≥ 近一年并行规划
- [ ] 副本与 ISR、保留时长满足补数
- [ ] 扩容 / 改键迁移路径有负责人
- [ ] 与 Flink / 消费组命名、DLQ 策略一并评审
8. 迁移路径(改键 / 扩容)
| 变更 | 推荐路径 |
|---|---|
| 只扩分区 | 扩容 → 调消费者并行 → 观察 lag 与再均衡 |
| 改分区键 | 新 Topic → 双写 → 下游切读 → 停旧 |
| 大客户隔离 | 独立 Topic + 路由,避免污染公共分区 |
常见坑(至少牢记这些)
按「机器核数」拍分区数,不问顺序与热点
核数变了主题却不能减分区,历史包袱难清。粗粒度业务键导致永久热点
大渠道单分区打满,总分区再多也救不了该键。扩分区当降 lag 唯一手段
若根因是 Sink 反压,扩分区只是把火烧得更散。先看消费瓶颈类型。改分区键不评迁移
下游按「同分区有序」做的状态机会乱。改键=契约变更。replication=1 上生产
Broker 宕机即丢未同步数据。生产至少 3 副本 + ISR 策略。
如何验收(可量化)
合并前 checklist,全勾才算本篇实践落地:
- [ ] 设计文档写清:分区键、是否有序、分区数推导、保留与副本
- [ ] 压测或线上峰值:单分区字节/消息占比无长期过高(如 > 30%)
- [ ] 消费者并行度与分区数匹配策略有说明
- [ ] 扩容演练:扩分区后消费正常、lag 可回落
- [ ] 若有序:抽同 key 消息在单分区内顺序校验通过
- [ ] 热点大户有隔离方案(加盐 / 独立 Topic)或书面接受风险
bash
kafka-run-class.sh kafka.tools.GetOffsetShell \
--broker-list ${brokers} --topic ods_ad_spend_event --time -1sql
SELECT channel_id, COUNT(*) AS cnt
FROM ods_ad_spend_detail_di
WHERE dt = '${biz_date}'
GROUP BY channel_id
ORDER BY cnt DESC
LIMIT 20;与 Lag / 反压的关系
分区不够或热点时,Kafka 积压排查 会表现为少数分区堆积;盲目扩消费者无效。若 Sink 反压,先读 Flink 反压,再决定是否扩分区。
上线后一周内复盘一次单分区占比,超阈值则启动加盐或拆题。
附:上线检查口头禅
键是否高基数、分区数是否留余量、消费并行度能否对齐、有序语义是否写清、扩容是否做过演练——五项过完再切流量。高峰后再观察至少一个完整业务周期,确认无新的热点分区与 rebalance 风暴。
相关面试题
占位:与题库小程序对齐后补链接(建议关联:分区与并行度、有序消费、再均衡、热点打散)。
改写说明:结构与判断标准参考 Wood 原创数仓/面试文,已改写成可执行清单;未包含未公开公司数据与内部表名。