Processing server request produce

Processing server request produce

1 Overview

In Producer Client side, Producer maintains a  ConcurrentMap<TopicPartition, Deque<RecordBatch>> batches variable, and based on the information topic-partition of the leader, leader BATCH on the same machine is placed in a request sent to the server, it saves a lot of network overhead and improve transmission effectiveness.

2, service processing

2.1 transmission request

The method of Producer Client sending the request to achieve the following:

 

 

After receiving the producer kafka request, through its network model, the final assembly process will be forwarded to KafkaApis

 

 

  • l View topic exists and whether the client has the appropriate permissions Desribe;
  • l The topic has Describe authority to see if there Write permissions;
  • l calling replicaManager.appendRecords () method of adding the record corresponding to the topic-partition has Write permission.

2.2 ReplicaManager

ReplicaManager, a copy of the Manager, the role is to manage all copies (replica) on this broker. In Kafka, each copy (replica) will now log instance (Log object) correspondence, a copy will correspond to a Log object.

ReplicaManager is not responsible for the specific log is created, it just managed Broker all partitions on . When you create an object Partition, Partition corresponding log is created for each replica by logManager object.

After ReplicaManager get the requested content, mainly to do the following things:

  • l acks disposed first determines whether a valid (effective three values ​​-1, 0), then directly returns invalid exception, no treatment;
  • l acks set effective, call appendToLocalLog () method will be added to the log records corresponding to the object in the local;
  • l appendToLocalLog () has been dealt with, if you find acks clients set = -1, that need additional copies of isr synchronization is complete to return response, it will create a DelayedProduce objects, waiting for the other copy of the isr synchronize, otherwise directly return result added.

 

 

appendToLocalLog() Implementation

 

 

Can be seen from the above appendToLocalLog () is implemented as follows:

  • l write first determines topic is not built Kafka topic, topic built Producer is not allowed to write;
  • l Partition to find an object corresponding topic-partition, if you find the corresponding partition in allPartitions, then directly call partition.appendRecordsToLeader () method append the appropriate records, otherwise it will throw an exception to the client.

ReplicaManager in the additional records, the call is Partition  appendRecordsToLeader() method, partiton component is a copy of the abstract of the topic on a broker. Each partition will maintain a target object is Replica, Replica object but also to maintain the Log object, that is, abstract data directory, specifically to achieve the following:

 

 

To get messages from the component parititon replicaManager

  • l first determine whether he is a leader, only the leader can receive producer request and write data
  • l is determined whether the current number of current ISR smaller than minInSyncReplicas, if the number is less than the ISR will throw an exception minInSyncReplicas
  • l the news to their own management component handles Log

2.3 Log

Log对象是对partition数据目录的抽象。管理着某个topic在某个broker的一个partition,它可能是一个leader,也可能是replica。同时,Log对象还同时管理着多个LogSegment,也就是日志的分段。

在 Log 对象的初始化时,有三个变量是比较重要的:

  • l  nextOffsetMetadata:可以叫做下一个偏移量元数据,它包括 activeSegment 的下一条消息的偏移量,该 activeSegment 的基准偏移量及日志分段的大小;
  • l  activeSegment:指的是该 Log 管理的 segments 中那个最新的 segment(这里叫做活跃的 segment),一个 Log 中只会有一个活跃的 segment,其他的 segment 都已经被持久化到磁盘了;
  • l  logEndOffset:表示下一条消息的 offset,它取自 nextOffsetMetadata 的 offset,实际上就是活动日志分段的下一个偏移量。

 

 

 

 

 

Server 将每个分区的消息追加到日志中时,是以 segment 为单位的,当 segment 的大小到达阈值大小之后,会滚动新建一个日志分段(segment)保存新的消息,而分区的消息总是追加到最新的日志分段(也就是 activeSegment)中。每个日志分段都会有一个基准偏移量(segmentBaseOffset,或者叫做 baseOffset),这个基准偏移量就是分区级别的绝对偏移量,而且这个值在日志分段是固定的。有了这个基准偏移量,就可以计算出来每条消息在分区中的绝对偏移量,最后把数据以及对应的绝对偏移量写到日志文件中。append() 方法的过程可以总结如下:

  • l  analyzeAndValidateRecords():对这批要写入的消息进行检测,主要是检查消息的大小及 crc 校验;
  • l  trimInvalidBytes():会将这批消息中无效的消息删除,返回一个都是有效消息的 MemoryRecords;
  • l  LogValidator.validateMessagesAndAssignOffsets():为每条消息设置相应的 offset(绝对偏移量) 和 timestrap;
  • l  maybeRoll():判断是否需要新建一个 segment 的,如果当前的 segment 放不下这批消息的话,需要新建一个 segment;
  • l  segment.append():向 segment 中添加消息;
  • l  更新 logEndOffset 和判断是否需要刷新磁盘(如果需要的话,调用 flush() 方法刷到磁盘)。
  • 关于 timestrap 的设置,这里也顺便介绍一下,在新版的 Kafka 中,每条 msg 都会有一个对应的时间戳记录,producer 端可以设置这个字段 message.timestamp.type 来选择 timestrap 的类型,默认是按照创建时间,只能选择从下面的选择中二选一:
  • l  CreateTime,默认值;
  • l  LogAppendTime。

在 Log 的 append() 方法中,会调用 maybeRoll() 方法来判断是否需要进行相应日志分段操作,其具体实现如下:

 

 

从 maybeRoll() 的实现可以看到,是否需要创建新的日志分段,有下面几种情况:

  • l  当前日志分段的大小加上消息的大小超过了日志分段的阈值(log.segment.bytes);
  • l  距离上次创建日志分段的时间达到了一定的阈值(log.roll.hours),并且数据文件有数据;
  • l  索引文件满了;
  • l  时间索引文件满了;
  • l  最大的 offset,其相对偏移量超过了正整数的阈值。

创建一个 segment 对象,真正的实现是在 Log 的 roll() 方法中,创建 segment 对象,主要包括三部分:数据文件、offset 索引文件和 time 索引文件。

2.4 offset索引文件

这里顺便讲述一下 offset 索引文件,Kafka 的索引文件有下面几个特点:

  • l  采用 绝对偏移量+相对偏移量 的方式进行存储的,每个 segment 最开始绝对偏移量也是其基准偏移量;
  • l  数据文件每隔一定的大小创建一个索引条目,而不是每条消息会创建索引条目,通过 index.interval.bytes 来配置,默认是 4096,也就是4KB;
  • 这样做的好处也非常明显:
  • l  因为不是每条消息都创建相应的索引条目,所以索引条目是稀疏的;
  • l  索引的相对偏移量占据4个字节,而绝对偏移量占据8个字节,加上物理位置的4个字节,使用相对索引可以将每条索引条目的大小从12字节减少到8个字节;
  • l  因为偏移量有序的,再读取数据时,可以按照二分查找的方式去快速定位偏移量的位置;
  • l  这样的稀疏索引是可以完全放到内存中,加快偏移量的查找。

2.5LogSegment写入

真正的日志写入,还是在 LogSegment 的 append() 方法中完成的,LogSegment 会跟 Kafka 最底层的文件通道、mmap 打交道。

 

 

  • l  logSegment底层使用了fileChannel写日志,写完之后还会判断是否要更新当前logSegment的最大时间戳
  • l  每当写入消息的大小积累到一定程度时,会新插入一条索引记录。这个积累的大小和配置index.interval.bytes有关系

kafka底层的写数据是根据fileChannel来写的,它写的时候不会立刻刷盘,而是开启了一个定时任务根据策略去刷盘。但是在默认情况下,这个定时任务又是不刷盘的(刷盘策略都不满足),kafka把刷盘的时机交给操作系统来掌控。

 


总结上述的流程如下图所示

 

 

 

3参考资料:

https://blog.csdn.net/u013332124/article/details/82778419

http://matt33.com/2018/03/18/kafka-server-handle-produce-request/

 

Guess you like

Origin www.cnblogs.com/zhy-heaven/p/10994064.html