#创建Topic bin/kafka-topics.sh --create --topic test --bootstrap-server localhost:9092 kafka创建topic不是这样的吗,经常看到说根据key的hash值来指定partition,这啥意思,我看命令创建topic也没有key啊
指定key,自动根据key来计算partition id是谁的行为,是kafka自动完成的吗,还是java的api完成的
kafka-topics.sh):是在搭建“容器”。你只需要定义这个容器有几个分区(Partitions),不需要关心具体的 Key。1. 创建 Topic 时发生了什么?
1bin/kafka-topics.sh --create --topic test --bootstrap-server localhost:9092test 的主题”。--partitions 参数,Kafka 会使用配置文件中的默认分区数(通常是 1 或根据 broker 数量决定)。1# 创建一个有 3 个分区的 topic 2bin/kafka-topics.sh --create --topic test --bootstrap-server localhost:9092 --partitions 3 --replication-factor 12. “根据 Key 的 Hash 值指定 Partition”是什么意思?
send() 方法时,你可以选择带 Key 发送,也可以不带 Key 发送。情况 A:发送消息时指定了 Key
Key = "user_123", Value = "..."。情况 B:发送消息时没有指定 Key (Key = null)
3. 代码层面的对比
1// 没有指定 Key,Kafka 会自动轮询分配到 partition 0, 1, 2... 2ProducerRecord<String, String> record = new ProducerRecord<>("test", "message content"); 3producer.send(record);1// 指定了 Key "order_888" 2// Kafka 计算 hash("order_888") % 3 (假设有3个分区) 3// 假设结果是 1,那这条消息一定去 partition 1 4// 下次再发 key 为 "order_888" 的消息,还会去 partition 1 5ProducerRecord<String, String> record = new ProducerRecord<>("test", "order_888", "message content"); 6producer.send(record);总结
kafka-topics.sh 只是负责“建房子”(定义分区数量),不需要知道将来住进来的人(Key)是谁。Hash(Key) % 分区数 →→ 固定落入某个分区(保证有序)。--partitions 数量以支撑并发。详细流程拆解
1. 用户调用 API (你的代码)
1// 你传入了 key: "user_123" 2ProducerRecord<String, String> record = new ProducerRecord<>("test", "user_123", "data"); 3producer.send(record);record 对象里只有 Topic 名称和 Key,还没有 Partition ID。2. 客户端拦截器与分区器 (Java Client 内部)
kafka-clients.jar)在将消息放入发送缓冲区之前,会执行一个关键步骤:计算分区。org.apache.kafka.clients.producer.Partitionerorg.apache.kafka.clients.producer.internals.DefaultPartitionerrecord 是否指定了 Partition。如果没有(通常是这种情况)。partitioner.partition(topic, key, ...)。
hash(key) % numPartitions。3. 网络发送
Partition ID = 2 的消息,通过网络发送给 Broker。1{ 2 "topic": "test", 3 "partition": 2, // <--- 注意:这里已经是确定的数字了 4 "key": "user_123", 5 "value": "data" 6}4. Broker 接收 (Kafka 服务端)
partition: 2,直接把消息追加到本地磁盘上对应的 test-2 日志文件中。UnknownTopicOrPartitionException。为什么要设计成客户端计算?
Key,Broker 收到后需要计算 Hash、查找元数据、决定分区,然后再写入。这会增加 Broker 的 CPU 负担和网络往返的延迟。特殊情况:自定义分区策略
Hash(Key) 策略,你可以自己写一个类实现 Partitioner 接口,告诉客户端怎么算。1public class MyCustomPartitioner implements Partitioner { 2 @Override 3 public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { 4 // 获取该 topic 的分区总数 5 List<PartitionInfo> partitions = cluster.partitionsForTopic(topic); 6 int numPartitions = partitions.size(); 7 8 if ("VIP_USER".equals(key)) { 9 return 0; // 强制发到分区 0 10 } else { 11 // 其他用户随机或轮询 12 return Math.abs(new Random().nextInt()) % numPartitions; 13 } 14 } 15 // ... 其他方法省略 16}1props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, MyCustomPartitioner.class.getName());