Kafka中关于分区的一些理解

分区和主题
一般我们会在一个topic下设置多个分区,这样多个分区对应多个消费者,以此可以提高kafka的吞吐量,相当于处理消息时达到了多线程并行执行的效果。

在这里插入图片描述

分区和消息
当生产者要向某个主题发送消息时,生产者会先将消息序列化处理,然后根据topic,serializedKey,serializedValue计算出当前消息应该发送到哪个分区中,默认情况下如果没有指定key值,则按照类似轮询分区数的方式发送,如果指定了key值,则根据key值进行hash后取模发送,所以同一个key值得消息会始终被发送到一个分区中,也就是会始终被一个消费者消费到(考虑可以实现消息的顺序性,但同时会造成资源分配不均衡,降低消息处理的能力)。

发送时指定key的情况下

往topic为"test_topic"的主题中,指定key值,生产10条消息

生产消息

for (int i = 0; i < 10; i++) {
	kafkaTemplate.send("test_topic", "test_topic_key", String.valueOf(i));
}

接收消息

@KafkaListener(topics = {"test_topic"})
public void listen(ConsumerRecord<?, ?> record) {
    logger.info("get msg key: {}, value: {}, partition: {}", record.key(), record.value().toString(), record.partition());
}

一共有4个分区
在这里插入图片描述

从结果可以看出,指定了key的情况下,所有的消息都发送到了分区0上
在这里插入图片描述
如果发送时不指定key
从结果可以看出,如果不指定key的情况下,有的消息在分区1上,有的消息在分区3上。
在这里插入图片描述

kafka自定义分区器
如果有时候我们在发送消息需要通过key值来进行一些业务上的划分,但key又会造成消息始终只能发送的一个消费者中,导致处理能力降低,那么这时候就可以通过自定义分区的方式,让有key值的消息也能按照比较均衡的方式发送消息。

自定义分区器

public class MySelfPartitioner implements Partitioner {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    public int partition(String topic, Object key, byte[] keyBytes,
                         Object value, byte[] valueBytes, Cluster cluster) {
        logger.info("use MySelfPartitioner ...");
        //拿到主题中的分区信息
        List<PartitionInfo> partitionInfos = cluster.partitionsForTopic(topic);
        //获取分区数
        int num = partitionInfos.size();
        //计算value的hashcode,然后取模,获取一个分区
        int parId = value.hashCode()%num;
        return parId;
    }

    public void close() {
    }

    public void configure(Map<String, ?> configs) {
    }
}

新增一个配置属性

public Map<String, Object> producerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers);
        props.put(ProducerConfig.RETRIES_CONFIG, retries);
        props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize);
        props.put(ProducerConfig.LINGER_MS_CONFIG, linger);
        props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        //设置自定义分区器
        props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "com.wyl.config.MySelfPartitioner");
        return props;
    }

可以看出,虽然指定了key,但是已经明显不是一个分区了,而是根据value取模计算后获取对应分区
在这里插入图片描述

分区和消费者的对应关系

  1. 当分区和消费者数量相同时,一个分区对应一个消费者。
  2. 当分区数大于消费者数时,那么会出现一个消费者对应多个分区。
  3. 当分区数小于消费者数时,多出来的消费者将不会消费任何消息。

在这里插入图片描述

分区再均衡
当我们消费者数量发生变化,或者分区数发生变化,那么kafka就需要重写计算分区和消费者的对应关系,这种现象就叫做分区再均衡。一般情况下要尽量避免分区再均衡的发生,因为这会造成消费者无法读取消息,当时消费者会通过心跳来和broker保持连接,如果消费者长时间不发送心跳那么broker就为认为这个消费者已经挂掉了,那么也会造成分区再均衡的发生。

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值