點擊上方“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
關閉超限連接
往期推薦
目前交流羣已有 800+人,旨在促進技術交流,可關注公衆號添加筆者微信邀請進羣
喜歡文章,點個“在看、點贊、分享”素質三連支持一下~
本文分享自微信公衆號 - JavaEdge(Java-Edge)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。