之前我们知道,生产者在拿到topic的元数据信息后,就是分区,分区主要是看生产者是按照什么策略来分区的
public class KafkaProducer<K, V> implements Producer<K, V> {
private int partition(ProducerRecord<K, V> record, byte[] serializedKey, byte[] serializedValue, Cluster cluster) {
/**
* 有分配分区号,直接使用
* 没分区号:
*/
Integer partition = record.partition();
return partition != null ?
partition :
partitioner.partition(
record.topic(), record.key(), serializedKey, record.value(), serializedValue, cluster);
}
}
public class DefaultPartitioner implements Partitioner {
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
/**
* 发送消息对应的topic对应的分区信息
*/
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
/**
* 分区个数
*/
int numPartitions = partitions.size();
/**
* 两种策略:
* 1.key为空
* 2.key不为空
*/
if (keyBytes == null) {
/**
* key为空,有一个计数器记录消息的个数
* 当前消息在这个topic的个数对可用分区的取模,就是采用轮询来发送
*/
int nextValue = nextValue(topic);
List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
if (availablePartitions.size() > 0) {
int part = Utils.toPositive(nextValue) % availablePartitions.size();
return availablePartitions.get(part).partition();
} else {
// no partitions are available, give a non-available partition
return Utils.toPositive(nextValue) % numPartitions;
}
} else {
// hash the keyBytes to choose a partition
/**
* key不为空
* key取hash值,对分区取模,同一个key会发送到同一个分区
*/
return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
}
}
}
从上面可以看到,如果没有分配分区,那么kafka使用自己的策略来分配,kafka自己的策略是如果key为空,则采用轮询的机制,如果不为空,则采用key的hash机制