持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
kafka生产者分区
分区的好处
1、可以合理的利用资源,一个Partition只对应一个Broker,一个Broker可以管理多个Partition,方便实现负载均衡。
2、提高并行度,分区个数变多后,生产者可以以分区为单位反射数据,消费者以分区为单位消费数据,同一时间同一消费组内可以有的消费者可以更多,消费能力增强
生产者的分区策略
1、生产者发送消息首先要构造ProducerRecord 对象,该对象Topic和值 Value,主题和值是必须要声明的,Partition分区和Key键可以不用指定,详细的6个构造函数如下。
public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value, Iterable<Header> headers) {
if (topic == null) {
throw new IllegalArgumentException("Topic cannot be null.");
} else if (timestamp != null && timestamp < 0L) {
throw new IllegalArgumentException(String.format("Invalid timestamp: %d. Timestamp should always be non-negative or null.", timestamp));
} else if (partition != null && partition < 0) {
throw new IllegalArgumentException(String.format("Invalid partition: %d. Partition number should always be non-negative or null.", partition));
} else {
this.topic = topic;
this.partition = partition;
this.key = key;
this.value = value;
this.timestamp = timestamp;
this.headers = new RecordHeaders(headers);
}
}
public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) {
this(topic, partition, timestamp, key, value, (Iterable)null);
}
public ProducerRecord(String topic, Integer partition, K key, V value, Iterable<Header> headers) {
this(topic, partition, (Long)null, key, value, headers);
}
public ProducerRecord(String topic, Integer partition, K key, V value) {
this(topic, partition, (Long)null, key, value, (Iterable)null);
}
public ProducerRecord(String topic, K key, V value) {
this(topic, (Integer)null, (Long)null, key, value, (Iterable)null);
}
public ProducerRecord(String topic, V value) {
this(topic, (Integer)null, (Long)null, (Object)null, value, (Iterable)null);
}
ProducerRecord构造函数说明
1、前四个构造方法,指定了partition的具体值,所有发送的消息都会写入到该分区下。
2、第五个没有分区具体的值,但是有key值,这时会计算key的hash值,然后hash值与分区数量取模来得到具体发送到哪一个分区。
例如:key1的hash值=5,topic的partition数=2,那么key1 对应的value1写入1号分区。
3、最后一种没有具体的分区值,也没有key值,那么将使用Sticky Partition(黏性分区器)随机选择一个分区,并且会尽可能一直 使用该分区,等待该分区的batch(批次)满了或者者linger.ms设置的时间到了,Kafka再随机一个分区进行使用(和上一次的分区不同,如果和上一次相同那么会再次随机一个分区,直至不相同)。
分区器
1、上面接受的就是DefaultPartitioner 默认分区。
2、UniformStickyPartitioner 纯粹的粘性分区策略
- 是不管你有没有key, 统一都用粘性分区来分配
3、RoundRobinPartitioner 分区策略
- 如果消息中指定了分区,则使用它
- 将消息平均的分配到每个分区中。
- 与key无关
自定义分区器
在一些特殊情况下,kafka提供的默认的分区策略不能满足我们的需要,我们就要自己构建我们自己的生产者的分区策略。比如把消息value钟带有hello的发往0号分区,带world的发送1好分区。
步骤
(1)定义类实现 Partitioner 接口。 (2)重写 partition()方法。
(3)使用分区器的方法,在生产者的配置中添加分区器参数,该自定义类的全路径。
public class MyPartitioner implements Partitioner {
@Override
public int partition(String s, Object o, byte[] bytes, Object value, byte[] bytes1, Cluster cluster) {
String msgValue = value.toString();
// 创建 partition
int partition;
// 判断消息是否包含 atguigu
if (msgValue.contains("hello")){
partition = 0;
}else if (msgValue.contains("world")){
partition = 1;
}else {
partition = 2;
}
// 返回分区号
return partition;
}
@Override
public void close() {
}
@Override
public void onNewBatch(String topic, Cluster cluster, int prevPartition) {
Partitioner.super.onNewBatch(topic, cluster, prevPartition);
}
@Override
public void configure(Map<String, ?> map) {
}
// 添加自定义分区器
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.baiyan.kafka.MyPartitioner");
总结
kafka采用分区的模式,可以很方便的实现负载均衡,并且分区数量设置的合理可以提高消费者的并行度,提高消费者的消费效率。