public class KafkaProducer<K, V> implements Producer<K, V> {
    private final Logger log;
    /** clientId 生成器,如果没有明确指定客户端 ID,则使用该字段顺序生成一个 */
    private static final AtomicInteger PRODUCER_CLIENT_ID_SEQUENCE = new AtomicInteger(1);
    private static final String JMX_PREFIX = "kafka.producer";
    public static final String NETWORK_THREAD_PREFIX = "kafka-producer-network-thread";
    public static final String PRODUCER_METRIC_GROUP_NAME = "producer-metrics";

    /** 生产者唯一标识(对应 client.id 属性配置 ) */
    private final String clientId;
    // Visible for testing
    final Metrics metrics;
    /** 分区选择器(对应 partitioner.class 属性配置),如果未明确指定分区,则基于一定的策略为消息选择合适的分区 */
    private final Partitioner partitioner;
    /** 消息的最大长度(对应 max.request.size 配置,包含消息头、序列化之后的 key 和 value) */
    private final int maxRequestSize;
    /** 发送单条消息的缓冲区大小(对应 buffer.memory 配置) */
    private final long totalMemorySize;
    /** kafka 集群元数据 */
    private final ProducerMetadata metadata;
    /** 消息收集器,用于收集并缓存消息,等待 Sender 线程的发送 */
    private final RecordAccumulator accumulator;
    /** 消息发送线程对象 */
    private final Sender sender;
    /** 消息发送线程 */
    private final Thread ioThread;
    /** 压缩算法(对应 compression.type 配置) */
    private final CompressionType compressionType;
    private final Sensor errors;
    /** 时间戳工具 */
    private final Time time;
    /** key 序列化器(对应 key.serializer 配置) */
    private final Serializer<K> keySerializer;
    /** value 序列化器(对应 value.serializer 配置) */
    private final Serializer<V> valueSerializer;
    /** 封装配置信息 */
    private final ProducerConfig producerConfig;
    /** 等待更新 kafka 集群元数据的最大时长 */
    private final long maxBlockTimeMs;
    /** 发送拦截器(对应 interceptor.classes 配置),用于待发送的消息进行拦截并修改,也可以对 ACK 响应进行拦截处理 */
    private final ProducerInterceptors<K, V> interceptors;
    private final ApiVersions apiVersions;
    private final TransactionManager transactionManager;
}

生产者初始化如下:

KafkaProducer(Map<String, Object> configs,
                  Serializer<K> keySerializer,
                  Serializer<V> valueSerializer,
                  ProducerMetadata metadata,
                  KafkaClient kafkaClient,
                  ProducerInterceptors interceptors,
                  Time time) {
        ProducerConfig config = new ProducerConfig(ProducerConfig.addSerializerToConfig(configs, keySerializer,
                valueSerializer));
        try {
            // 获取用户配置信息
            Map<String, Object> userProvidedConfigs = config.originals();
            this.producerConfig = config;
            this.time = time;

            String transactionalId = userProvidedConfigs.containsKey(ProducerConfig.TRANSACTIONAL_ID_CONFIG) ?
                    (String) userProvidedConfigs.get(ProducerConfig.TRANSACTIONAL_ID_CONFIG) : null;
            // 尝试获取用户配置的 clientId,如果未配置则基于 PRODUCER_CLIENT_ID_SEQUENCE 顺序生成一个
            this.clientId = buildClientId(config.getString(ProducerConfig.CLIENT_ID_CONFIG), transactionalId);

            LogContext logContext;
            if (transactionalId == null)
                logContext = new LogContext(String.format("[Producer clientId=%s] ", clientId));
            else
                logContext = new LogContext(String.format("[Producer clientId=%s, transactionalId=%s] ", clientId, transactionalId));
            log = logContext.logger(KafkaProducer.class);
            log.trace("Starting the Kafka producer");

            Map<String, String> metricTags = Collections.singletonMap("client-id", clientId);
            MetricConfig metricConfig = new MetricConfig().samples(config.getInt(ProducerConfig.METRICS_NUM_SAMPLES_CONFIG))
                    .timeWindow(config.getLong(ProducerConfig.METRICS_SAMPLE_WINDOW_MS_CONFIG), TimeUnit.MILLISECONDS)
                    .recordLevel(Sensor.RecordingLevel.forName(config.getString(ProducerConfig.METRICS_RECORDING_LEVEL_CONFIG)))
                    .tags(metricTags);
            List<MetricsReporter> reporters = config.getConfiguredInstances(ProducerConfig.METRIC_REPORTER_CLASSES_CONFIG,
                    MetricsReporter.class,
                    Collections.singletonMap(ProducerConfig.CLIENT_ID_CONFIG, clientId));
            reporters.add(new JmxReporter(JMX_PREFIX));
            this.metrics = new Metrics(metricConfig, reporters, time);
            // 获取配置的分区器对象(反射创建)
            this.partitioner = config.getConfiguredInstance(ProducerConfig.PARTITIONER_CLASS_CONFIG, Partitioner.class);
            // 获取生产者重试间隔
            long retryBackoffMs = config.getLong(ProducerConfig.RETRY_BACKOFF_MS_CONFIG);
            // 如果参数未指定 key 序列化器,则尝试从配置中获取 key 序列化器对象(反射创建)
            if (keySerializer == null) {
                this.keySerializer = config.getConfiguredInstance(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
                                                                                         Serializer.class);
                this.keySerializer.configure(config.originals(), true);
            } else {
                config.ignore(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG);
                this.keySerializer = keySerializer;
            }
            // 如果参数未指定 value 序列化器,则尝试从配置中获取 value 序列化器对象(反射创建)
            if (valueSerializer == null) {
                this.valueSerializer = config.getConfiguredInstance(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
                                                                                           Serializer.class);
                this.valueSerializer.configure(config.originals(), false);
            } else {
                config.ignore(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG);
                this.valueSerializer = valueSerializer;
            }

            // load interceptors and make sure they get clientId
            userProvidedConfigs.put(ProducerConfig.CLIENT_ID_CONFIG, clientId);
            ProducerConfig configWithClientId = new ProducerConfig(userProvidedConfigs, false);
            // 获取注册的拦截器列表
            List<ProducerInterceptor<K, V>> interceptorList = (List) configWithClientId.getConfiguredInstances(
                    ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, ProducerInterceptor.class);
            if (interceptors != null)
                this.interceptors = interceptors;
            else
                this.interceptors = new ProducerInterceptors<>(interceptorList);
            ClusterResourceListeners clusterResourceListeners = configureClusterResourceListeners(keySerializer,
                    valueSerializer, interceptorList, reporters);
            // 获取并设置生产者发送请求的大小
            this.maxRequestSize = config.getInt(ProducerConfig.MAX_REQUEST_SIZE_CONFIG);
            // 获取并设置生产者内存缓冲区大小,用于缓存要发送到服务器的消息
            this.totalMemorySize = config.getLong(ProducerConfig.BUFFER_MEMORY_CONFIG);
            // 获取并设置消息压缩算法,可以设置为 snappy、gzip 或 lz4,默认不压缩。
            this.compressionType = CompressionType.forName(config.getString(ProducerConfig.COMPRESSION_TYPE_CONFIG));

            this.maxBlockTimeMs = config.getLong(ProducerConfig.MAX_BLOCK_MS_CONFIG);
            this.transactionManager = configureTransactionState(config, logContext, log);
            int deliveryTimeoutMs = configureDeliveryTimeout(config, log);

            this.apiVersions = new ApiVersions();
            // 创建消息收集器,用于异步发送消息
            this.accumulator = new RecordAccumulator(logContext,
                    config.getInt(ProducerConfig.BATCH_SIZE_CONFIG),
                    this.compressionType,
                    lingerMs(config),
                    retryBackoffMs,
                    deliveryTimeoutMs,
                    metrics,
                    PRODUCER_METRIC_GROUP_NAME,
                    time,
                    apiVersions,
                    transactionManager,
                    new BufferPool(this.totalMemorySize, config.getInt(ProducerConfig.BATCH_SIZE_CONFIG), metrics, time, PRODUCER_METRIC_GROUP_NAME));
            // 获取 kafka 集群主机列表
            List<InetSocketAddress> addresses = ClientUtils.parseAndValidateAddresses(
                    config.getList(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG),
                    config.getString(ProducerConfig.CLIENT_DNS_LOOKUP_CONFIG));
            if (metadata != null) {
                this.metadata = metadata;
            } else {
                // 创建并更新 kafka 集群的元数据信息
                this.metadata = new ProducerMetadata(retryBackoffMs,
                        config.getLong(ProducerConfig.METADATA_MAX_AGE_CONFIG),
                        logContext,
                        clusterResourceListeners,
                        Time.SYSTEM);
                this.metadata.bootstrap(addresses);
            }
            this.errors = this.metrics.sensor("errors");
            // 创建并启动 Sender 线程
            this.sender = newSender(logContext, kafkaClient, this.metadata);
            String ioThreadName = NETWORK_THREAD_PREFIX + " | " + clientId;
            this.ioThread = new KafkaThread(ioThreadName, this.sender, true);
            this.ioThread.start();
            // 打印未使用的配置
            config.logUnused();
            AppInfoParser.registerAppInfo(JMX_PREFIX, clientId, metrics, time.milliseconds());
            log.debug("Kafka producer started");
        } catch (Throwable t) {
            // call close methods if internal objects are already constructed this is to prevent resource leak. see KAFKA-2121
            close(Duration.ofMillis(0), true);
            // now propagate the exception
            throw new KafkaException("Failed to construct kafka producer", t);
        }
    }

Metadata 定义
        保存集群元数据信息的 Metadata 类的字段定义:

public class Metadata implements Closeable {
    private final Logger log;
    /** 元数据最小更新时间间隔,默认是 100 毫秒,防止更新太频繁 */
    private final long refreshBackoffMs;
    /** 元数据更新时间间隔,默认为 5 分钟 */
    private final long metadataExpireMs;
    /** 元数据版本号,每更新成功一次则版本号加 1 */
    private int updateVersion;  // bumped on every metadata response
    /** 上一次更新元数据的时间戳,不管成功还是失败 */
    private long lastRefreshMs;
    private int requestVersion; // bumped on every new topic addition
    /** 上一次成功更新元数据的时间戳 */
    private long lastSuccessfulRefreshMs;
    private KafkaException fatalException;
    private Set<String> invalidTopics;
    private Set<String> unauthorizedTopics;
    private MetadataCache cache = MetadataCache.empty();
    /** 标记是否需要更新集群元数据信息 */
    private boolean needUpdate;
    private final ClusterResourceListeners clusterResourceListeners;
    private boolean isClosed;
    private final Map<TopicPartition, Integer> lastSeenLeaderEpochs;
}

Cluster
         Cluster 类是对集群节点、topic、分区等信息的一个封装,其字段定义如下:

public final class Cluster {
    private final boolean isBootstrapConfigured;
    /** kafka 集群中的节点信息列表(包括 id、host、port 等信息) */
    private final List<Node> nodes;
    /** 未授权的 topic 集合 */
    private final Set<String> unauthorizedTopics;
    private final Set<String> invalidTopics;
    /** 内部 topic 集合 */
    private final Set<String> internalTopics;
    private final Node controller;
    /** 记录 topic 分区与分区详细信息的映射关系 */
    private final Map<TopicPartition, PartitionInfo> partitionsByTopicPartition;
    /** 记录 topic 及其分区信息的映射关系 */
    private final Map<String, List<PartitionInfo>> partitionsByTopic;
    /** 记录 topic 及其分区信息的映射关系(必须包含 leader 副本) */
    private final Map<String, List<PartitionInfo>> availablePartitionsByTopic;
    /** 记录节点 ID 与分区信息的映射关系 */
    private final Map<Integer, List<PartitionInfo>> partitionsByNode;
    /** key 是 brokerId,value 是 broker 节点信息,方便基于 brokerId 获取对应的节点信息 */
    private final Map<Integer, Node> nodesById;
    private final ClusterResource clusterResource;
}

RecordAccumulator 
        消息收集器,可以将其看做是一个本地缓存消息的队列,消息收集线程将消息最终记录到收集器中,而 Sender 线程会定期定量从收集器中取出缓存的消息,并投递给 Kafka 集群。

public final class RecordAccumulator {

    private final Logger log;
    /** 标识当前收集器是否被关闭,对应 producer 被关闭 */
    private volatile boolean closed;
    /** 记录正在执行 flush 操作的线程数 */
    private final AtomicInteger flushesInProgress;
    /** 记录正在执行 append 操作的线程数 */
    private final AtomicInteger appendsInProgress;
    /** 指定每个 RecordBatch 中 ByteBuffer 的大小 */
    private final int batchSize;
    /** 消息压缩类型 */
    private final CompressionType compression;
    /** 通过参数 linger.ms 指定,当本地消息缓存时间超过该值时,即使消息量未达到阈值也会进行投递 */
    private final int lingerMs;
    /** 生产者重试时间间隔 */
    private final long retryBackoffMs;
    private final int deliveryTimeoutMs;
    /** 缓存(ByteBuffer)管理工具 */
    private final BufferPool free;
    /** 时间戳工具 */
    private final Time time;
    private final ApiVersions apiVersions;
    /** 记录 topic 分区与 RecordBatch 的映射关系,对应的消息都是发往对应的 topic 分区 */
    private final ConcurrentMap<TopicPartition, Deque<ProducerBatch>> batches;
    /** 记录未发送完成(即未收到服务端响应)的消息集合 */
    private final IncompleteBatches incomplete;
    // The following variables are only accessed by the sender thread, so we don't need to protect them.
    /**
     * 消息顺序性保证,
     * 缓存当前待发送消息的目标 topic 分区,防止对于同一个 topic 分区同时存在多个未完成的消息,可能导致消息顺序性错乱
     */
    private final Map<TopicPartition, Long> muted;
    /** 记录 drain 方法批量导出消息时上次的偏移量 */
    private int drainIndex;
    private final TransactionManager transactionManager;
    private long nextBatchExpiryTimeMs = Long.MAX_VALUE; // the earliest time (absolute) a batch will expire.
    }

ProducerBatch

       从上面 RecordAccumulator 类的字段列表中我们看到有一个 ConcurrentMap<TopicPartition, Deque<ProducerBatch>> 类型的 batches 字段,这里的 key 对应 topic 的某个分区,而 value 是一个 Deque 类型,其中封装了一批 ProducerBatch 对象,这些对象中记录了待发送的消息集合,而这些消息的一个共同点就是都是发往相同的 topic 分区。ProducerBatch 类字段定义如下:

public final class ProducerBatch {

    private static final Logger log = LoggerFactory.getLogger(ProducerBatch.class);

    private enum FinalState { ABORTED, FAILED, SUCCEEDED }
    /** 当前 RecordBatch 创建的时间戳 */
    final long createdMs;
    /** 当前缓存的消息的目标 topic 分区 */
    final TopicPartition topicPartition;
    /** 标识当前 RecordBatch 发送之后的状态 */
    final ProduceRequestResult produceFuture;
    /** 消息的 Callback 队列,每个消息都对应一个 Callback 对象 */
    private final List<Thunk> thunks = new ArrayList<>();
    /** 用来存储数据的 {@link MemoryRecords} 对应的 builder 对象 */
    private final MemoryRecordsBuilder recordsBuilder;
    /** 发送当前 RecordBatch 的重试次数 */
    private final AtomicInteger attempts = new AtomicInteger(0);
    private final boolean isSplitBatch;
    private final AtomicReference<FinalState> finalState = new AtomicReference<>(null);

    /** 记录保存的 record 个数 */
    int recordCount;
    /** 记录最大的 record 字节数 */
    int maxRecordSize;
    /** 最后一次重试发送的时间戳` */
    private long lastAttemptMs;
    /** 追后一次向当前 RecordBatch 追加消息的时间戳 */
    private long lastAppendTime;
    /** 记录上次投递当前 BatchRecord 的时间戳 */
    private long drainedMs;
    /** 标记是否正在重试 */
    private boolean retry;
    private boolean reopened;
}