kafka producer 核心流程

producer.send(new ProducerRecord<>(topic,
-> doSend
    private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) {
    
    
        TopicPartition tp = null;
        try {
    
    
            /**
             * 步骤一:
             *      同步等待拉取元数据。
             *  maxBlockTimeMs 最多能等待多久。
             */
            ClusterAndWaitTime clusterAndWaitTime = waitOnMetadata(record.topic(), record.partition(), maxBlockTimeMs);
            
            //clusterAndWaitTime.waitedOnMetadataMs 代表的是拉取元数据用了多少时间。
            //maxBlockTimeMs -用了多少时间 = 还剩余多少时间可以使用。
            long remainingWaitMs = Math.max(0, maxBlockTimeMs - clusterAndWaitTime.waitedOnMetadataMs);
            //更新集群的元数据
            Cluster cluster = clusterAndWaitTime.cluster;
           
            /**
             * 步骤二:
             *  对消息的key和value进行序列化。
             */
            byte[] serializedKey;
            try {
    
    
                serializedKey = keySerializer.serialize(record.topic(), record.key());
            } catch (ClassCastException cce) {
    
    
                throw new SerializationException("Can't convert key of class " + record.key().getClass().getName() +
                        " to class " + producerConfig.getClass(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG).getName() +
                        " specified in key.serializer");
            }
            byte[] serializedValue;
            try {
    
    
                serializedValue = valueSerializer.serialize(record.topic(), record.value());
            } catch (ClassCastException cce) {
    
    
                throw new SerializationException("Can't convert value of class " + record.value().getClass().getName() +
                        " to class " + producerConfig.getClass(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG).getName() +
                        " specified in value.serializer");
            }
            
            /**
             * 步骤三:
             *  根据分区器选择消息应该发送的分区。
             *
             *  因为前面我们已经获取到了元数据
             *  这儿我们就可以根据元数据的信息
             *  计算一下,我们应该要把这个数据发送到哪个分区上面。
             */
            int partition = partition(record, serializedKey, serializedValue, cluster);

            int serializedSize = Records.LOG_OVERHEAD + Record.recordSize(serializedKey, serializedValue);
            /**
             * 步骤四:
             *  确认一下消息的大小是否超过了最大值。
             *  KafkaProdcuer初始化的时候,指定了一个参数,代表的是Producer这儿最大能发送的是一条消息能有多大
             *  默认最大是1M,我们一般都回去修改它。
             */
            ensureValidRecordSize(serializedSize);
            
            /**
             * 步骤五:
             *  根据元数据信息,封装分区对象
             */
            tp = new TopicPartition(record.topic(), partition);
            long timestamp = record.timestamp() == null ? time.milliseconds() : record.timestamp();
            log.trace("Sending record {} with callback {} to topic {} partition {}", record, callback, record.topic(), partition);
            // producer callback will make sure to call both 'callback' and interceptor callback
           
            /**
             * 步骤六:
             *  给每一条消息都绑定他的回调函数。因为我们使用的是异步的方式发送的消息。
             */
            Callback interceptCallback = this.interceptors == null ? callback : new InterceptorCallback<>(callback, this.interceptors, tp);
            
            /**
             * 步骤七:
             *  把消息放入accumulator(32M的一个内存)
             *  然后有accumulator把消息封装成为一个批次一个批次的去发送。
             */
            RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey, serializedValue, interceptCallback, remainingWaitMs);
            
            //如果批次满了
            //或者新创建出来一个批次
            if (result.batchIsFull || result.newBatchCreated) {
    
    
                log.trace("Waking up the sender since topic {} partition {} is either full or getting a new batch", record.topic(), partition);
                /**
                 * 步骤八:
                 *  唤醒sender线程。他才是真正发送数据的线程。
                 */
                this.sender.wakeup();
            }
            return result.future;

猜你喜欢

转载自blog.csdn.net/m0_46449152/article/details/114852378