1)默认的分区器:Defaultpartitioner,ctrl+n 全局搜索DefaultPartitioner,可以在源码中查看分区策略
#如果记录中指定了分区,请使用它
1) If a partition is specified in the record, use it
#如果未指定分区但存在key,根据key的哈希值选择分区
2) If no partition is specified but a key is present choose a partition based on a hash of the key
#如果为指定分区且不存在key的情况下,选择在批处理已满的时更改为粘性分区
3) If no partition or key is present choose the sticky partition that changes when the batch is full.
ctrl+n,全局搜索ProducerRecord可以查看到对应策略的源码,前四个对应策略一、第五个对应策略二、第六个对应策略三。
(1)、指明partition的情况下,直接将知名的值作为partition的值。例:partition=0,将所有数据写入分区0.
(2)、没有指明partition值但有key的情况下,将key的hash值与topic的partition数进行取余得到partition值。例:key1的hash值为5,key2的hash值为6,topic的分区数(partition)数为2。5%2=1,那么key1对应的value写入1号分区;6%2=0,那么key2对应的value写入0号分区.
(3)、既没有partition值又没有key值得情况下,kafka采用Sticky Partition(黏性分区),会随机选择一个分区,并尽可能一致使用该分区,待该分区得batch已满或者已完成,Kafka在随机一个分区进行使用(和上一次得分区不同,如果相同,则会继续随机,直到找到不同得分区为止)
例:第一次随机选择0号分区,等0好分区当前批满了(默认16K)或者linger.ms设置得时间到,kafka在随机选择一个分区进行使用。
2)自定义分区器
(1)定义类实现Partitioner接口
(2)重写partition()方法
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import java.util.Map;
/**
* 文件名:MyDefinePartitioner
* 创建者:CYS
* 创建时间: 2022/10/20 15:47
* 描述: 自定义分区器:实现发送过来的数据中如果包含huarui,就发往2号分区,不包含huarui的就发往1号分区
* 1) 继承Partitioner
* 2) 实现接口的三个方法:partition、close、configure
*/
public class MyDefinePartitioner implements Partitioner {
@Override
/**
*
* @Param
* @param topic 主题名
* @param key 消息的Key
* @param keyBytes 消息Key序列化后的字节数
* @param value 消息的value
* @param valueBytes 消息的value序列化后的字节数
* @param cluster 集群元数据可以查看的分区信息
* @return int 返回分区号
**/
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
//获取消息
String msgValue = value.toString();
//创建partition
int partition;
//判断消息是否包含huarui
if(msgValue.contains("huarui")){
partition=2;
}else{
partition=1;
}
//返回分区号
return partition;
}
//关闭资源
@Override
public void close() {
}
//配置方法
@Override
public void configure(Map<String, ?> configs) {
}
}
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.util.Properties;
/**
* 文件名:CustomProducerCallbackPartitions
* 创建者:CYS
* 创建时间: 2022/10/20 16:00
* 描述:
*/
public class CustomProducerCallbackPartitions {
public static void main(String[] args) {
//1、创建配置对象
Properties properties = new Properties();
//2、配置kafka参数
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop01:9092,hadoop02:9092,hadoop03:9092");
//2.1 k、v序列化
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringDeserializer.class);
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringDeserializer.class);
//2.2 添加自定义分区器
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "com.cys.kafka.mydefine.MyDefinePartitioner");
//2.3 创建生产者
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
//2.4 发送数据
for (int i = 0; i < 5; i++) {
kafkaProducer.send(new ProducerRecord<>("first", "cys"), new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if ("null".equals(exception)) {
System.out.println("topic:" + metadata.topic() + "-->" + "分区:" + metadata.partition());
}else{
exception.printStackTrace();
}
}
});
}
//3、关闭资源
kafkaProducer.close();
}
}