圖文講解Kafka如何應用NIO實現網絡通信


  點擊上方“JavaEdge”,關注公衆號

設爲“星標”,好文章不錯過!


網絡通信層




Kafka網絡通信組成



  • SocketServer

    核心,主要實現了Reactor模式,用於處理外部多個Clients(廣義Clients,可能包含Producer、Consumer或其他Broker)的併發請求,並負責將處理結果封裝進Response中,返還給Clients。SocketServer是Kafka網絡通信層中最重要的子模塊。它的Acceptor線程、Processor線程和RequestChannel等對象,都是實施網絡通信的重要組成部分。

  • KafkaRequestHandlerPool

    I/O線程池,裏面定義了若干個I/O線程,用於執行真實的請求處理邏輯。KafkaRequestHandlerPool線程池定義了多個KafkaRequestHandler線程,而KafkaRequestHandler線程是真正處理請求邏輯的地方。


兩者共通處在於SocketServer中定義的RequestChannel對象和Processor線程。在代碼中,線程本質都是Runnable類型,不管是Acceptor類、Processor還是KafkaRequestHandler類。

相較於KafkaRequestHandler,Acceptor和Processor最多算請求和響應的“搬運工”。


SocketServer



  • AbstractServerThread類 這是Acceptor線程和Processor線程的抽象基類

  • Acceptor線程類 接收和創建外部TCP連接的線程。每個SocketServer實例只會創建一個Acceptor線程。唯一作用創建連接,並將接收到的Request傳遞給下游的Processor線程。

  • Processor線程類 每個SocketServer實例默認創建若干個(num.network.threads)Processor線程。負責

    • 將接收到的Request添加到RequestChannel的Request隊列

    • 將Response返還給Request發送方

  • Processor伴生對象類 僅定義一些與Processor線程相關的常見監控指標和常量等,如Processor線程空閒率等。

  • ConnectionQuotas類 

  • TooManyConnectionsException類 

  • SocketServer類 實現了對以上所有組件的管理和操作,如創建和關閉Acceptor、Processor線程。

  • SocketServer伴生對象類 定義了一些有用的常量,同時明確了SocketServer組件中的哪些參數是允許動態修改的。




Acceptor線程



經典Reactor模式的Dispatcher接收外部請求並分發給下面的實際處理線程。在Kafka中,這個Dispatcher就是Acceptor線程。


參數



endPoint

定義的Kafka Broker連接信息,比如PLAINTEXT://localhost:9092 

sendBufferSize

recvBufferSize

如果在你的生產環境中,Clients與Broker的通信網絡延遲很大(RTT>10ms),推薦增加控制緩衝區大小的兩個參數:sendBufferSize和recvBufferSize,一般默認值100KB太小了。


Acceptor線程的自定義屬性



  • nioSelector Java NIO庫的Selector對象實例,也是後續所有網絡通信組件實現Java NIO機制的基礎

  • processors 網絡Processor線程池。Acceptor線程在初始化時,需要創建對應的網絡Processor線程池。Processor線程是在Acceptor線程中管理和維護的。


Processor相關API



  • addProcessors  

  • removeProcessors 於是Acceptor類就具備Processor線程池管理功能。

  • Acceptor類的run方法 - 處理Reactor模式中分發 

Acceptor線程會先爲每個入站請求確定要處理它的Processor線程

Acceptor線程使用Java NIO的Selector、SocketChannel循環輪詢就緒的I/O事件(SelectionKey.OP_ACCEPT)。一旦接收到外部連接請求,Acceptor就指定一個Processor線程,並將該請求交由它,讓它創建真正的網絡連接。




Processor線程



  • 源碼 

  • 執行流程 

  • 每個Processor線程在創建時都會創建3個隊列:可能是阻塞隊列,也可能是一個Map對象

newConnections

 每當Processor線程接收新連接請求,都會將對應SocketChannel放入該隊列。之後調用configureNewConnections創建連接時,就從該隊列中取出SocketChannel,然後註冊新連接。

inflightResponses

  • 臨時Response隊列 

  • 爲何是臨時?有些Response回調邏輯要在Response被返回發送方後,才能執行,因此需要暫存臨時隊列。

responseQueue

每個Processor線程都會維護自己的Response隊列, 而非像網上的某些文章說Response隊列是線程共享的或是保存在RequestChannel中的。Response隊列裏面保存着需要被返還給發送方的所有Response對象。

工作邏輯

configureNewConnections

  • 負責處理新連接請求,注意每個Processor線程都維護着一個Selector類實例。 

processNewResponses

  • 負責發送Response給Request發送方,並且將Response放入臨時Response隊列 

poll

processCompletedReceives

  • 接收和處理Request 

processCompletedSends

processDisconnected

closeExcessConnections

  • 關閉超限連接 


往期推薦


大廠如何解決數值精度/舍入/溢出問題

硬核乾貨:HTTP超時、重複請求必見坑點及解決方案

由於不知線程池的bug,某Java程序員叕被祭天

程序員因重複記錄日誌撐爆ELK被辭退!

擁抱Kubernetes,再見了Spring Cloud




目前交流羣已有 800+人,旨在促進技術交流,可關注公衆號添加筆者微信邀請進羣


喜歡文章,點個“在看、點贊、分享”素質三連支持一下~

本文分享自微信公衆號 - JavaEdge(Java-Edge)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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