考察点
这是设计题,没有标准答案,面试官看的是你建模的思路:分区是 Kafka 唯一的并行单位,定多少直接影响吞吐上限、消费并行度和集群负载。有序性部分考你是否清楚"Kafka 只保证分区内有序"这个基本事实,以及乱序的真实来源(多分区、重试、max.in.flight)。能给出量化推算过程比背原则值钱得多。
参考答案
分区数从哪几个维度推
分区是并行度的天花板:同一消费者组内,一个分区同一时刻只能被一个实例消费,实例数超过分区数就是闲置。所以分区数的第一约束来自消费并行度,第二约束来自吞吐目标。
量化的算法:先测出单分区的消费速率(比如压测得到单实例单分区每秒处理 1000 条),业务峰值是每秒 2 万条,那消费侧至少需要 20 个分区。生产侧同理测单分区写入速率。两边取大,再加 1-2 倍余量应对峰值和扩容期,就是目标分区数。注意压测要用真实消息大小和真实处理逻辑,单分区吞吐和消息大小强相关,别人的数字(比如"单分区 10MB/s")没法直接抄。
分区数不是越多越好,代价要说得出来:
- 每个分区在 Broker 上对应文件句柄和内存(副本 buffers),几万个分区会明显抬高 Broker 内存占用和 Controller 故障恢复时间(Leader 选举按分区逐个进行,分区越多全量故障恢复越慢)。
- 端到端延迟会变差:Producer 攒批按分区进行,分区多意味着同样的消息量摊到更多批次里,batch 更碎。
- 客户端元数据、心跳负担都随分区数涨。
经验值:单 Broker 上分区副本数控制在几千以内比较稳,单个主题几十到几百个分区是常见区间。分区只能加不能减(减了已存数据没法处理),所以宁可一开始略多,也别拍脑袋上几千个。
有序性的真实边界:只在单个分区内成立
Kafka 保证的是同一分区内,消息按写入顺序存储、按顺序被消费。跨分区没有任何顺序保证。这个模型决定了:要保序,必须把"需要有序的消息"路由进同一个分区。
实现手段是消息的 key:Producer 指定 key 后,默认分区器对 key 做 murmur2 哈希取模,相同 key 永远进同一分区。订单场景按订单 ID 作 key,同一个订单的创建、支付、完成事件就严格有序;不同订单之间并发处理,互不影响——这就是"局部有序换取整体并行"的标准玩法,和分库分表按 ID 路由是同一个思想。
要求全局有序(全主题就一个流)?那就只能 1 个分区,吞吐天花板也只有一个分区。真遇到这种需求,先反推一下是不是设计有问题——多数"全局有序"其实按某个业务 ID 分 key 就够了。
单分区内也可能乱序:重试的坑
即使单分区,Producer 端也可能制造乱序:开了重试且 max.in.flight.requests.per.connection > 1 时,第一批发送失败进入重试队列,第二批先成功写入,顺序就反了。解决方案两个:
- 开幂等(
enable.idempotence=true),Broker 按序列号校验,乱序写入直接被拒,这个场景下 in-flight 可以安全放到 5。 - 不开幂等就把
max.in.flight.requests.per.connection设为 1,吞吐换顺序。
分区与扩缩容的连锁反应
分区数定了之后不是一劳永逸,要预判两件事:一是消费者组扩容——分区数决定了消费并行度上限,业务增长期前就要留够;二是加分区会打乱已有 key 的路由(哈希取模的模数变了),同一个 key 加分区前后落到不同分区,老分区内该 key 的历史消息和新分区内的新消息之间无法保证顺序。对强有序要求的业务,加分区要停写迁移,或者接受一个时间窗内的乱序,这是架构设计阶段就要想清楚的。
key 倾斜也要防:少数热点 key(比如大促时的爆款商品)会把对应分区打爆。对策是热点 key 拆分(key 加随机后缀散到多个分区,消费端再聚合),或者业务层削峰。
可能的追问
- 分了 key 之后,消费端还需要做什么保证有序吗? 单线程消费一个分区天然有序;但如果消费端做了多线程异步处理,就要按 key 再散列到固定线程,否则分区内的顺序会被并发处理打乱。
- 分区副本数和分区数是一回事吗? 不是。分区数定并行度,副本数(replication.factor)定可靠性,一般 3。面试官故意混着问是想看你概念清不清。
- 怎么估算一个集群总共能放多少分区? 按 Broker 内存、文件句柄、Controller 恢复时间评估,每 Broker 几千副本是经验上限;超大规模考虑多集群拆分而不是单集群硬撑。