Kafka生产者提交数据流程+源码解析

Kafka生产者提交数据流程

在平时的工作中,经常需要引入消息队列中间件,Kafka作为目前主流的消息队列,是程序员必不可少的技能。
本文结合kafka-clients源码回顾一下Kafka生产者提交数据的流程。kafka-clients版本为3.3.1,Java版本kafka-clients的maven路径:

<dependency>
   <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>3.3.1</version>
</dependency>

一、Kafka生产者提交数据整体流程

按照先整体再局部的方法,先复习一下Kafka生产者提交数据的整体流程,然后再从整体出发,剖析各个部分的细节。
Kafka生产者提交数据流程+源码解析_第1张图片

  1. Kafka发送之前需要创建KafkaProducer,调用send方法提交数据。
public class KafkaSendDemo {

    public static void main(String[] args) {
        Properties properties = new Properties();
        // 设置kafka集群地址
        properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"");
        // 设置key/value序列化方法
        properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        // 创建生产者
        KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
        // 发送数据
        Future<RecordMetadata> send = producer.send(new ProducerRecord<>("topic1", 1, "hello", "hello"));

    }
}

Kafka支持同步提交和异步提交:同步提交调用send(ProducerRecord)方法; 异步提交调用send(ProducerRecord, Callback)方法。

  1. 调用send方法提交数据后,会接入拦截器,在拦截器中可以对数据进行过滤、转换等操作。通过实现 ProducerInterceptor接口,并实现onSend方法可以自定义拦截器。随后在创建KafkaProducer时设置配置项interceptor.classes的值指定拦截器。
public class MyProducerInterceptor implements ProducerInterceptor<String, String> {
    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
        return null;
    }

    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {

    }

    @Override
    public void close() {

    }

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

    }
}
  1. 通过拦截器的数据会进入序列化器,在序列化器中对数据的key/value进行序列化操作。

  2. 序列化过后,Kafka会对数据进行分区,确定数据将写入topic中的哪个分区。确认分区的逻辑流程为:

    • 第一步,判断是否直接指定了分区,如果指定了分区直接退出;
    • 第二步,未指定分区的数据,判断是否指定了分区器,如果指定了分区器,则使用指定的分区策略设置分区。
    • 第三步,未指定分区且未设置分区器的数据,判断是否有key且key不应该被忽略,如果满足,则分区为:key哈希值对topic分区数量取模;否则返回-1,表示可以使用任意分区,后续使用内部逻辑确定分区(一般为随机分区)。
  3. 确认分区后,将数据放入累积器中,累积器的作用为:设置一个内存阈值和时间阈值,当数据累积到一定大小或到达时间节点,则向服务端传输数据,可以提高数据传输效率,内存阈值初始值为16KB。

  4. 通过Sender将满足条件的数据发送到服务端。

二、从源码中体现整个流程

1.发送数据,最终都是调用send(ProducerRecord record, Callback callback)方法。
在这里插入图片描述
send(ProducerRecord record, Callback callback)方法:
Kafka生产者提交数据流程+源码解析_第2张图片

2.执行拦截器,在send(ProducerRecord record, Callback callback)方法中,首先调用this.interceptors.onSend(record)方法,对已注册的拦截器进行一一调用。
interceptors类型为ProducerInterceptors,改变量初始化逻辑为:如果在创建KafkaProducer是传入interceptors,则直接使用传入的interceptors;否则
从配置中获取 ProducerConfig.INTERCEPTOR_CLASSES_CONFIG配置值,创建interceptors。
Kafka生产者提交数据流程+源码解析_第3张图片
this.interceptors.onSend(record)方法,遍历interceptors中的每个interceptor,每个interceptor执行onSend(record)方法,最后返回经过拦截器处理的数据。
Kafka生产者提交数据流程+源码解析_第4张图片
3.序列化器
在执行序列化器之前,会先进行一些其他操作,如:

  • 将数据封装成AppendCallbacks对象,主要作用是当数据发送完成后调用拦截器的onAcknowledgement()方法;记录数据在topic中的分区号。
  • waitOnMetadata()方法检查更新topic信息,检查生产者是否关闭。

对key/value 进行序列化操作:
Kafka生产者提交数据流程+源码解析_第5张图片
4.分区器
调用partition(ProducerRecord record, byte[] serializedKey, byte[] serializedValue, Cluster cluster)计算数据的分区。

你可能感兴趣的:(java,kafka,java,分布式)