news 2026/10/21 11:23:06

KafkaProducer 分区策略:一条消息怎么被分到正确的 Partition

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
KafkaProducer 分区策略:一条消息怎么被分到正确的 Partition

为什么分区策略很重要

前面几篇一直在讲"消息进了 RecordAccumulator 之后怎么发"。但有个问题没回答:同一条消息,为什么会被塞进 topic-A 的 P0 而不是 P1?

这个决定发生在partitioner.partition()这一步。它看起来简单——返回一个整数——但这个整数决定了三件事:

  • 这条消息和哪些消息攒成一个 batch(同分区才会攒批)
  • 消费端谁来处理(分区决定消费者分配)
  • 消息的顺序性(同 key 同分区才有序)

选错了,轻则批次攒不起来、吞吐上不去;重则某个分区被打爆、其他分区闲着。

01 Partitioner 接口:就三个方法

自定义分区器要实现Partitioner接口,核心是一个方法:

publicinterfacePartitionerextendsConfigurable,Closeable{intpartition(Stringtopic,Objectkey,byte[]keyBytes,Objectvalue,byte[]valueBytes,Clustercluster);voidclose();}

configure(Map)继承自 Configurable,拿到 Producer 全部配置。配置项:

partitioner.class=com.example.MyPartitioner

默认实现是DefaultPartitioner(2.4+ 内部用 StickyPartitioner)。它的逻辑就两条分支:

02 带 key:murmur2 hash,同 key 同分区

消息带 key 时:

intpartition=Utils.toPositive(Utils.murmur2(keyBytes))%numPartitions;

为什么用 murmur2 而不是String.hashCode()?因为 JDK 的 hashCode 分布不均匀——连续 key 会扎堆。murmur2 是 Kafka 专门选的,分布更均匀。

这个策略保证了一件事:同 key 的消息永远落同分区。所以 user_id=12345 的所有事件一定在同一个分区里,消费端按顺序处理。这就是"按用户维度做顺序消费"的基础。

代价是热点 key:如果某个 key(比如一个大促活动 ID)的数据量是其他 key 的 100 倍,那它所在的分区就成了热点——该分区所在的 Broker 网络打满,其他分区闲着。

03 不带 key:StickyPartitioner,先粘住再切

消息不带 key 时,老版本(2.4 之前)默认轮询——每条消息换一个分区。问题是攒批效果极差:10 个分区,每条消息换一个,每个分区平均只有几条消息,每个 batch 都是半满就发出去了。

2.4 之后默认改成StickyPartitioner:

// 伪代码:先随机选一个分区,粘住intstickyPartition=random.nextInt(numPartitions);// 攒满 batch.size 之前,所有无 key 消息都往这个分区塞// 攒满了,随机切下一个分区

短期看数据倾斜(全粘在一个分区),长期看均匀(每个 batch 切一次)。换来的好处是单批次更大——默认 16KB 的 batch.size 能真正攒满,网络请求更少。

这就是为什么第三篇讲 Sticky 分区器能提升吞吐——它牺牲了"短期均匀"换"批次填满"。

04 四种策略对比

策略分布顺序攒批问题
带 key hash均匀强顺序中热点 key
无 key 轮询均匀无差批次小
无 key Sticky长期均匀无好短期倾斜
自定义看实现可保看实现容易写歪

选择原则很简单:

  • 要顺序(同一实体的事件要按序处理)→ 带 key
  • 不要顺序(日志、埋点流)→ 用默认 Sticky,别手动设轮询
  • 有业务路由需求(按地域、灰度、租户隔离)→ 自定义 Partitioner

别为了"看起来均匀"去写自定义分区器——默认 Sticky 已经做得很好了。自定义分区器最常见的问题是上线前没压测分布,结果某个分区被打爆。

05 分区数怎么定

分区数决定了两件事:生产吞吐上限、消费并行度上限。

经验公式:

分区数 ≈ max(目标吞吐 / 单分区吞吐, 消费并行度) × 2
  • 单分区生产吞吐经验值约 10MB/s(压缩后更高)
  • 消费端并行度不能超过分区数——10 个分区开 20 个消费者线程,有 10 个闲着
  • 加分区只能加不能减,而且加分区会改变 key 的 hash 路由——原来 hash 到 P3 的 key,加了分区后可能落到 P7,同 key 的消息乱序

所以一开始就留余量。现在需要 10 个分区,直接建 20 个。一个 Broker 上分区数别超过 2000,集群总分区数别超过 20000——太多了 Leader 选举、元数据同步都会变慢。

06 热点 key 怎么拆

线上最常见的问题不是"分区太少",而是"某个 key 太大"。症状:JMX 看某分区 BytesInPerSec 远高于其他分区,kafka-lag 看某分区 lag 一直涨,该分区所在 Broker CPU 打满。

定位:

kafka-console-consumer--topicmy-topic\--bootstrap-server kafka:9092\--propertyprint.key=true\--from-beginning|head-10000|awk'{print $1}'|sort|uniq-c|sort-rn|head

哪几个 key 出现频率远超均值,就是热点。常见元凶:大促活动 ID、默认 key、空 key(空 key 走 Sticky 不会热点,别误判)。

拆法:key 加随机后缀。

// 原来:所有大促消息都落到 P3producer.send("big-sale-2024",data);// 改成:拆成 N 个子 key,分散到多分区intbucket=ThreadLocalRandom.current().nextInt(10);Stringkey="big-sale-2024-"+bucket;producer.send(key,data);

代价是同实体跨分区,失去单 key 顺序性。如果业务能接受(比如日志类),这是最简单的拆法。如果不能接受顺序,就得在消费端做归并,或者换业务 key 设计。

写在最后

分区策略不是"选一个算法"这么简单——它是吞吐、顺序、负载三者的权衡。带 key 换顺序,Sticky 换吞吐,自定义换灵活性。线上出问题最多的两种:带了 key 但 key 设计得太粗(导致热点),或者完全不带 key 但又想要顺序(不可能)。

实际项目里,90% 的场景用默认策略就够了:要顺序带业务 ID 做 key,不要顺序什么都别设。剩下 10% 有特殊路由需求的,才考虑自定义 Partitioner——而且上线前一定要压测分布。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 11:20:51

Unity游戏上架微信小游戏:适配全程与避坑实录

Unity游戏上架微信小游戏:适配全程与避坑实录 【免费下载链接】minigame-unity-webgl-transform 微信小游戏Unity引擎适配器文档。 项目地址: https://gitcode.com/GitHub_Trending/mi/minigame-unity-webgl-transform 把一个跑在手游端的 Unity 项目搬进微信…

作者头像 李华
网站建设 2026/10/21 11:16:14

Jasna 马赛克检测模型怎么选?7 个选项一篇看懂

Jasna 马赛克检测模型怎么选?7 个选项一篇看懂 【免费下载链接】jasna Video restoration tool 项目地址: https://gitcode.com/GitHub_Trending/ja/jasna Jasna 是一款开源的 JAV 视频马赛克修复工具:先由检测模型逐帧找出被遮挡区域&#xff0c…

作者头像 李华
网站建设 2026/10/21 11:14:33

OpenAI API 错误响应排查保姆级指南

OpenAI API 错误响应排查保姆级指南 【免费下载链接】openai-openapi OpenAPI specification for the OpenAI API 项目地址: https://gitcode.com/GitHub_Trending/op/openai-openapi 第一次调用 OpenAI API,终端吐回 401 Unauthorized,错误体里一…

作者头像 李华
网站建设 2026/10/21 11:00:21

UniHacker:跨平台 Unity 激活工具,3 分钟跑通

UniHacker:跨平台 Unity 激活工具,3 分钟跑通 【免费下载链接】UniHacker 为Windows、MacOS、Linux和Docker修补所有版本的Unity3D和UnityHub 项目地址: https://gitcode.com/GitHub_Trending/un/UniHacker UniHacker 是一款基于 Avalonia .NET …

作者头像 李华