深入理解kafka——RecordAccumulator 和 InFlightRequests

博主在這裏不具體討論生產者的代碼如何編寫,而是聚焦於生產者客戶端比較重要的兩個區域RecordAccumulator 和 InFlightRequests。

 

整個生產者客戶端由兩個線程協調工作,分別爲主線程和Sender線程。主線程中由KafkaProducer創建消息,然後會依次經過攔截器、序列化器、分區器,然後緩存到消息累加器,也稱爲RecordAccumulator。

而Sender線程則負責從RecordAccumulator中獲取消息,然後發送給Kafka集羣。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RecordAccumulator主要用來緩存消息,以便於Sender線程能夠批量發送,這裏有個生產者客戶端參數buffer.memory來配置大小,默認32MB。

主線程過來的消息會被追加到RecordAccumulator的某個雙端隊列(Deque)中——對應分區號,隊列的內容就是Deque<ProducerBatch>,這裏的ProduceeBatch包含一個或多個ProducerRecord。

RecordAccumulator內部還有個BufferPool,主要用來複用特定大小的ProducerBatch塊,這個特定大小會通過batch.size指定,默認爲16KB,例如說當有一條消息(ProducerRecord)流入RecordAccumulator,會先通過分區號尋找雙端隊列(如果沒有則創建),再從隊列的尾部獲取一個ProducerBatch(如果沒有則新建),查看ProducerBatch是否還可以裝的下這個ProducerRecord,如果可以則寫入,如果不可以則需創建個新的ProducerBatch。在新建ProducerBatch時會評估這個ProducerRecord的大小是否超過batch.size,也就是可複用ProducerBatch的大小,如果沒超過,那麼可以從BufferPool中拿個閒置的ProducerBatch來使用。如果超過,那麼就按實際的大小創建ProducerBatch,這個ProducerBatch不會再被複用。

 

Sender從RecordAccumulator獲取緩存的消息之後,會將原本的<分區,Deque<ProducerBatch>>轉換爲<Node,List<ProducerBatch>>,其中Node表示Kafka集羣的broker節點,之後Sender還會進一步封裝成<Node,Request>,這樣就可以將Request發送給各個Node了。

 

請求從Sender線程發往Kafka之前還會保存到InFlightRequests中,InFlightRequests顧名思義——飛行途中的請求,主要作用是緩存已經發出去但還沒有收到響應的請求,保存對象的具體形式爲Map<NodeId,Deque<Request>>,這裏有個重要的配置參數爲max.in.flight.requests.per.connection,默認值爲5,即每個連接最多隻能緩存5個未收到響應的請求,超過這個數值之後便不能再往這個連接發送更多的請求了,除非有緩存的請求收到了響應。這裏補充一點就是如果在需要保證消息順序的場合建議把max.in.flight.requests.per.connection設爲1,不過這樣也會影響整體的吞吐量

 

通過比較各個Node的Deque<Request>的size來判斷,哪個結點來不及處理消息,哪個結點處理消息很及時。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章