1.概述
kafka客户端通过KafkaProducer对象,然后指定具体的Topic和具体的消息即可将消息发送到Topic的某个分区,如果需要控制消息的路有规则,则需要指定分区的实现函数和分区的key。
2.重要类讲解
Cluster:代表一个当前kafka集群的nodes,topics和partitions子集
NetworkClient:一个针对异步请求/应答的网络IO 的网络客户端。这是一个内部类,用来实现用户层面的生产消费者客户端。非线程安全的。
Sender:一个后台线程,主要负责发送生产请求到kafka集群。该线程会更新kafka集群的metadata,将produce Request发送到正确的节点。
RecordAccumulator:该类内部维护的是一个ConcurrentMap<TopicPartition, Deque<ProducerBatch>> batches队列,将records追加到MemoryRecords实例中,用于发送到server端。
ProducerBatch:一批准备发送的消息。内部维护了一个MemoryRecordsBuilder,MemoryRecordsBuilder内部维护了一个MemoryRecords。
MemoryRecords:用一个byteBuffer支撑的Records的实现。producer传输数据和broker写入文件数据都是用这个传输。
3.源码
3.1 Producer实例化过程
producer = new KafkaProducer<>(props);
1) new Selector传递给NetworkClient
2) new NetworkClient
3) new Sender
4) new KafkaThread并将构建的send对象,当做该线程的runnable。并启动该线程。
5) new ProducerMetadata
6) new RecordAccumulator。此时需要关注的两个配置是: batch.size:批量发送的大小;linger.ms:超时发送的时间。
3.2 消息加入发送队列的过程
1) 调用KafkaProducer.send发送消息
private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) {
2) 对消息按照partition策略进行分区。
// 获取分区号
int partition = partition(record, serializedKey, serializedValue, cluster);
3) 将消息追加到RecordAccumulator。
// 将消息追加到RecordAccumulator
RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey,
serializedValue, headers, interceptCallback, remainingWaitMs, true, nowMs);
4) 根据topic和partition信息获取一个recordBatch,然后在获取MemoryRecords,将消息加入其中
// 先根据topic和partition信息获取一个ProducerBatch
Deque<ProducerBatch> dq = ge