kafka发送的消息是封装成批次发送的,这些操作都是在RecordAccumulator对象中操作的,下图是RecordAccumulator中的对象对应关系
首先看一下RecordAccumulator中的一些对应关系,生产者发送数据是分装在ProducerBatch中的,每个Partition对应一个Dequeue队列,这些队列组成批次batches,BufferPool是一个内存池,ProducerBatch对象的内存就是在内存池中申请的
封装批次流程
public RecordAppendResult append(TopicPartition tp,
long timestamp,
byte[] key,
byte[] value,
Header[] headers,
Callback callback,
long maxTimeToBlock) throws InterruptedException {
// We keep track of the number of appending thread to make sure we do not miss batches in
// abortIncompleteBatches().
appendsInProgress.incrementAndGet();
ByteBuffer buffer = null;
if (headers == null) headers = Record.EMPTY_HEADERS;
try {
// check if we have an in-progress batch
/**
* 1.根据分区获取对应的队列
*/
Deque<ProducerBatch> dq = getOrCreateDeque(tp);
synchronized (dq) {
/**
* 2.尝试往队列中的最后一个批次写数据,如果还没有分配内存,则添加数据失败
*/
if (closed)
throw new KafkaException("Producer closed while send in progress");
RecordAppendResult appendResult = tryAppend(timestamp, key, value, headers, callback, dq);
if (appendResult != null)
return appendResult;
}
/**
* 队列中没有批次,则创建批次
*/
// we don't have an in-progress record batch try to allocate a new batch
byte maxUsableMagic = apiVersions.maxUsableProduceMagic();
/**
* 3.计算一个批次的大小,默认16Kb
* 消息的大小和批次的大小取最大值作为批次的大小,原因是消息的大小有可能比批次的大小还大
* 如果发送数据的时候,消息的大小超过了批次的大小,那么消息会被一条一条发送出去,这样会影响性能
*/
int size = Math.max(this.batchSize, AbstractRecords.estimateSizeInBytesUpperBound(maxUsableMagic, compression, key, value, headers));
log.trace("Allocating a new {} byte message buffer for topic {} partition {}", size, tp.topic(), tp.partition());
/**
* 4.根据批次的大小分配内存
*/
buffer = free.allocate(size, maxTimeToBlock);
/**
* 5.再次尝试把数据写入对应的批次,第一次执行时,是失败的,因为还没有批次
*/
synchronized (dq) {
// Need to check if producer is closed again after grabbing the dequeue lock.