3. 默认分区策略(DefaultPartitioner):轮询与粘性分区,适用场景与局限性
说实话,很多刚接触Kafka的同学,上来就问我:「分区策略到底怎么选?」
我的回答通常是:先搞懂默认的。你连系统自带的DefaultPartitioner都没吃透,就别急着去搞什么自定义分区器了。
今天我们就来聊聊这个默认分区策略。它其实包含两种模式:轮询(Round-Robin)和粘性分区(Sticky Partitioner)。嗯,这里要注意,Kafka 2.4版本之后,默认行为已经变了。
3.1 轮询分区:最朴素的负载均衡
轮询策略,说白了就是「轮流来」。
假设你有3个分区,第一条消息去分区0,第二条去分区1,第三条去分区2,第四条又回到分区0。就这么简单粗暴。
我早期做日志采集系统时,用的就是纯轮询。那时候数据量不大,每个分区的消费速度也差不多,轮询确实省心。
但轮询有个明显的短板——批量效率低。为什么呢?
你想想看,轮询模式下,每条消息都可能发往不同的分区。这意味着Producer需要为每条消息单独创建一个批次(Batch)。如果消息体很小,比如就几百字节,那网络开销占比就很高了。
// 轮询模式下的伪代码示意
for (Message msg : messages) {
int partition = counter++ % partitionCount;
producer.send(new ProducerRecord<>(topic, partition, msg.key(), msg.value()));
}
这段代码看着简单,但实际跑起来,吞吐量往往上不去。我在项目中遇到过类似场景,单机TPS死活到不了10万,后来发现是轮询导致批次太小,频繁刷盘。
3.2 粘性分区:性能优化的产物
Kafka 2.4版本引入了粘性分区策略,现在已经是默认选项了。
它的思路很巧妙:先尽量往一个分区里塞消息,攒够一批再换下一个。
这样做的好处很明显:
- 批次更大:同一个分区的消息可以合并成更大的Batch,减少网络往返次数
- 吞吐量更高:实测下来,粘性分区比纯轮询能提升30%-50%的吞吐量
- 延迟更低:因为批次更容易填满,不需要等待超时
// 粘性分区策略的核心思想(简化版)
// 1. 选择一个分区作为"粘性"目标
// 2. 持续向该分区发送消息,直到批次满或达到linger.ms
// 3. 切换下一个分区
public int partition(String topic, byte[] key, byte[] value, Cluster cluster) {
// 实际源码中会维护一个粘性分区缓存
// 这里只展示逻辑
if (currentBatch.isFull() || isTimeout()) {
stickyPartition = nextPartition(cluster);
}
return stickyPartition;
}
我曾经帮一个金融客户调优Kafka性能,他们用的是老版本,轮询策略下吞吐量只有8MB/s。升级到2.4之后,什么都没改,直接飙到15MB/s。嗯,这就是粘性分区的威力。
3.3 适用场景分析
两种策略各有各的用武之地。我整理了一张表,方便你对照:
| 场景 | 推荐策略 | 原因 |
|---|---|---|
| 高吞吐写入(>10MB/s) | 粘性分区(默认) | 批次大,网络利用率高 |
| 消息体极小(<100字节) | 粘性分区 | 减少小消息的网络开销 |
| 严格均匀分布 | 轮询 | 粘性分区在切换前会有短暂倾斜 |
| 金融对账/流水场景 | 自定义分区(按key) | 需要保证同一订单的消息有序 |
| 测试环境/低负载 | 两者均可 | 差异不大,用默认就行 |
3.4 局限性:没有银弹
默认分区策略虽然好用,但也不是万能的。我总结了几个常见的坑:
- 无法保证消息顺序:如果你需要同一业务ID的消息进入同一个分区,默认策略做不到。必须用自定义分区器,按key哈希。
- 粘性分区有短暂倾斜:在切换分区之前,所有消息都集中在一个分区上。虽然整体均衡,但短时间内的负载是不均匀的。
- 无法感知消费者负载:默认策略只考虑分区数量,不考虑消费者的消费能力。如果某个消费者处理慢,它分配到的分区依然会收到同样多的消息。
- 不适合超大消息体:如果单条消息就几MB,粘性分区的批次优势就不明显了。反而可能因为批次太大导致内存压力。
说白了,默认分区策略是「通用方案」,不是「最优方案」。它适合大多数场景,但如果你有特殊需求,还是得自己动手。
3.5 知识体系总览
下面这张图,帮你理清默认分区策略的核心脉络:
3.6 我的建议
如果你刚开始接触Kafka,或者你的业务没有特殊的分区需求,直接用默认的粘性分区策略就好。别折腾。
但如果你遇到以下情况,就得考虑换策略了:
- 业务要求同一用户ID的消息必须有序 → 按key哈希分区
- 某些分区的消费者处理能力明显弱于其他 → 自定义分区或调整消费者
- 消息体极大(>1MB)且对延迟敏感 → 考虑减少批次大小或换策略
好了,默认分区策略就聊到这儿。记住一句话:默认的,不一定是最好的,但一定是最稳妥的起点。
公众号:蓝海资料掘金营,微信deep3321