kafak--producer生产消息2

本文详细介绍了Kafka Producer发送消息的具体流程,包括消息序列化、分区处理等关键步骤,并通过源码解析的方式深入探讨了消息发送过程中的实现细节。

kafka2.10-0.10.2.1

kafak–producer生产消息中学习了Producer发送消息,基本流程为5步
第一步:初始化kafka参数
第二步:创建生产者
第三步:创建一条消息
第四步:发送消息
第五步:异步发送中处理消息发送是否成功结果

下面使用一个流程图来表示发送消息到 Kafka 集群的基本步骤:
这里写图片描述

二、源码解析

2.1、序列化key,value

这里写图片描述

2.2、接着数据发送给分区器。如果在构造 ProducerRecord 对象的时候,声明了分区信息,分区器会判断分区信息是否正确,如果正确,直接返回我们声明的分区;如果我们没有声明分区信息,分区器将会选择一个分区,通常使用 key 信息来决定选择 topic 的哪个分区

这里写图片描述

2.3、具体业务在doSend

 /**
     * Implementation of asynchronously send a record to a topic.
     */
    private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) {
        TopicPartition tp = null;
        try {
            //序列化key, value 
            // first make sure the metadata for the topic is available
            ClusterAndWaitTime clusterAndWaitTime = waitOnMetadata(record.topic(), record.partition(), maxBlockTimeMs);
            long remainingWaitMs = Math.max(0, maxBlockTimeMs - clusterAndWaitTime.waitedOnMetadataMs);
            Cluster cluster = clusterAndWaitTime.cluster;
            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");
            }

            //获取partition
            int partition = partition(record, serializedKey, serializedValue, cluster);

            int serializedSize = Records.LOG_OVERHEAD + Record.recordSize(serializedKey, serializedValue);
            ensureValidRecordSize(serializedSize);
            //TopicPartition 包含 topic name and partition number
            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);
            //追加消息
            //向累加器添加一条记录,返回附加结果
            //附加结果将包含将来的元数据,以及是否附加的批处理已满或新的批创建的标志。
            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);
                this.sender.wakeup();
            }
            //返回响应结果
            return result.future;
            // handling exceptions and record the errors;
            // for API exceptions return them in the future,
            // for other exceptions throw directly
        } catch (ApiException e) {
            log.debug("Exception occurred during message send:", e);
            if (callback != null)
                callback.onCompletion(null, e);
            this.errors.record();
            if (this.interceptors != null)
                this.interceptors.onSendError(record, tp, e);
            return new FutureFailure(e);
        } catch (InterruptedException e) {
            this.errors.record();
            if (this.interceptors != null)
                this.interceptors.onSendError(record, tp, e);
            throw new InterruptException(e);
        } catch (BufferExhaustedException e) {
            this.errors.record();
            this.metrics.sensor("buffer-exhausted-records").record();
            if (this.interceptors != null)
                this.interceptors.onSendError(record, tp, e);
            throw e;
        } catch (KafkaException e) {
            this.errors.record();
            if (this.interceptors != null)
                this.interceptors.onSendError(record, tp, e);
            throw e;
        } catch (Exception e) {
            // we notify interceptor about all exceptions, since onSend is called before anything else in this method
            if (this.interceptors != null)
                this.interceptors.onSendError(record, tp, e);
            throw e;
        }
    }




    /**
     * A callback called when producer request is complete. It in turn calls user-supplied callback (if given) and
     * notifies producer interceptors about the request completion.
     */
    private static class InterceptorCallback<K, V> implements Callback {
        private final Callback userCallback;
        private final ProducerInterceptors<K, V> interceptors;
        private final TopicPartition tp;

        public InterceptorCallback(Callback userCallback, ProducerInterceptors<K, V> interceptors,
                                   TopicPartition tp) {
            this.userCallback = userCallback;
            this.interceptors = interceptors;
            this.tp = tp;
        }

        public void onCompletion(RecordMetadata metadata, Exception exception) {
            if (this.interceptors != null) {
                if (metadata == null) {
                    this.interceptors.onAcknowledgement(new RecordMetadata(tp, -1, -1, Record.NO_TIMESTAMP, -1, -1, -1),
                                                        exception);
                } else {
                    this.interceptors.onAcknowledgement(metadata, exception);
                }
            }
            if (this.userCallback != null)
                this.userCallback.onCompletion(metadata, exception);
        }
    }
1.入门 1.1简介 1.2用例 1.3快速入门 1.4生态系统 1.5升级 2. API 2.1生产者API 2.2消费者API 2.3 Streams API 2.4连接API 2.5 AdminClient API 2.6旧版API 3.配置 3.1经纪人配置 3.2主题配置 3.3制片人配置 3.4消费者配置 3.4.1新的消费者配置 3.4.2旧消费者配置 3.5 Kafka Connect配置 3.6 Kafka Streams配置 3.7 AdminClient配置 4.设计 4.1动机 4.2持久性 4.3效率 4.4制片人 4.5消费者 4.6消息传递语义 4.7复制 4。4日志压缩 4.9配额 5.实施 5.1网络层 5.2消息 5.3消息格式 5。4日志 5.5分配 6.运营 6.1基本卡夫卡业务 添加和删​​除主题 修改主题 优雅的关机 平衡领导力 检查消费者的位置 在群集之间镜像数据 扩展您的群集 退役经纪人 增加复制因子 6.2数据中心 6.3重要配置 重要客户端配置 生产服务器配置 6.4 Java版本 6.5硬件和操作系统 OS 磁盘和文件系统 应用程序与OS Flush Management Linux Flush Behavior Ext4笔记 6.6监测 6.7 ZooKeeper 稳定的版本 操作化 7.安全 7.1安全概述 7.2使用SSL进行加密和身份验证 7.3使用SASL进行身份验证 7.4授权和ACL 7.5在正在运行的群集中加入安全功能 7.6 ZooKeeper认证 新集群 迁移群集 迁移ZooKeeper Ensemble 8. KAFKA CONNECT 8.1概述 8.2用户指南 运行Kafka Connect 配置连接器 转换 REST API 8.3连接器开发指南 9. KAFKA STREAMS 9.1使用Streams应用程序 9.2编写自己的Streams应用程序 9.3开发者手册 9.4核心概念 9.5架构 9.6升级指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值