Java IO篇之Reactor 網絡模型的概念

一、什麼是 Reactor 模型:

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.

Reactor 模式也叫做反應器設計模式,是一種為處理服務請求並發提交到一個或者多個服務處理器的事件設計模式。當請求抵達後,通過服務處理器將這些請求采用多路分離的方式分發給相應的請求處理器。Reactor 模式主要由 Reactor 和處理器 Handler 這兩個核心部分組成,如下圖所示,它倆負責的事情如下:

  • Reactor:負責監聽和分發事件,事件類型包含連接事件、讀寫事件;
  • Handler :負責處理事件,如 read -> 業務邏輯 (decode + compute + encode)-> send;

在絕大多數場景下,處理一個網絡請求有如下幾個步驟:

① read:從 socket 讀取數據。
② decode:解碼,網絡上的數據都是以 byte 的形式進行傳輸的,要想獲取真正的請求,必需解碼
③ compute:計算,也就是業務處理。
④ encode:編碼,網絡上的數據都是以 byte 的形式進行傳輸的,也就是 socket 隻接收 byte,所以必需編碼。
⑤ send:發送應答數據

        對於Reactor模式來說,每當有一個 Event 輸入到 Server 端時,Service Handler 會將其轉發(dispatch)相對應的 Handler 進行處理。Reactor 模型中定義的三種角色:

Reactor:派發器,負責監聽和分配事件,並將事件分派給對應的 Handler。新的事件包含連接建立就緒、讀就緒、寫就緒等。

Acceptor:請求連接器,處理客戶端新連接。Reactor 接收到 client 端的連接事件後,會將其轉發給 Acceptor,由 Acceptor 接收 Client 的連接,創建對應的 Handler,並向 Reactor 註冊此 Handler。

Handler:請求處理器,負責事件的處理,將自身與事件綁定,執行非阻塞讀/寫任務,完成 channel 的讀入,完成處理業務邏輯後,負責將結果寫出 channel。可用資源池來管理。

模型大致如下圖所示:

 對於讀/寫請求,Reactor 模型是按照以下流程處理的:

  • (1)應用程序註冊讀/寫就緒事件和相關聯的事件處理器
  • (2)事件分離器等待事件的發生
  • (3)當發生讀/寫就緒事件的時候,事件分離器調用第一步註冊的事件處理器

二、Reactor 模型的分類:

Reactor 模型中的 Reactor 可以是單個也可以是多個,Handler 同樣可以是單線程也可以是多線程,所以組合的模式大致有如下三種:

  • 單 Reactor 單線程模型
  • 單 Reactor 多線程模型
  • 主從 Reactor 單線程模型
  • 主從 Reactor 多線程模型

其中第三種的主從Reactor單線程模型沒什麼實際意義,所以下文就著重介紹其他三種模型

1、單 Reactor 單線程模型:

1.1、處理流程:

(1)Reactor 線程通過 select 監聽事件,收到事件後通過 Dispatch 進行分發

(2)如果是連接建立事件,則將事件分發給 Acceptor,Acceptor 會通過 accept() 方法獲取連接,並創建一個Handler 對象來處理後續的響應事件

(3)如果是IO讀寫事件,則 Reactor 會將該事件交由當前連接的 Handler 來處理

(4)Handler 會完成 read -> 業務處理 -> send 的完整業務流程

1.2、優缺點:

        單 Reactor 單線程模型的優點在於將所有處理邏輯放在一個線程中實現,沒有多線程、進程通信、競爭的問題。但該模型在性能與可靠性方面存在比較嚴重的問題:

  • ① 性能:隻在代碼上進行組件的區分,整體操作還是單線程,無法充分利用 CPU 資源,並且 Handler 業務處理部分沒有異步,一個 Reactor 既要負責處理連接請求,又要負責處理讀寫請求,一般來說處理連接請求是很快的,但處理讀寫請求時涉及到業務邏輯處理,相對慢很多。所以 Reactor 在處理讀寫請求時,其他請求隻能等著,容易造成系統的性能瓶頸
  • ② 可靠性:一旦 Reactor 線程意外中斷或者進入死循環,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障

        所以該單Reactor單進程模型不適用於計算密集型的場景,隻適用於業務處理非常快速的場景。Redis的線程模型就是基於單 Reactor 單線程模型實現的,因為 Redis 業務處理主要是在內存中完成,操作的速度是很快的,性能瓶頸不在 CPU 上,所以 Redis 對於命令的處理是單進程的。

2、單 Reactor 多線程模型:

        為瞭解決單Reactor單線程模型存在的性能問題,就演進出瞭單 Reactor 多線程模型,該模型在事件處理器部分采用瞭多線程(線程池)

2.1、處理流程:

 (1)Reactor 線程通過 select 監聽事件,收到事件後通過 Dispatch 進行分發

(2)如果是連接建立事件,則將事件分發給 Acceptor,Acceptor 會通過 accept() 方法獲取連接,並創建一個Handler 對象來處理後續的響應事件

(3)如果是IO讀寫事件,則 Reactor 會將該事件交由當前連接對應的 Handler 來處理

(4)與單Reactor單線程不同的是,Handler 不再做具體業務處理,隻負責接收和響應事件,通過 read 接收數據後,將數據發送給後面的 Worker 線程池進行業務處理。

(5)Worker 線程池再分配線程進行業務處理,完成後將響應結果發給 Handler 進行處理。

(6)Handler 收到響應結果後通過 send 將響應結果返回給 Client。

2.2、優缺點:

        相對於第一種模型來說,在處理業務邏輯,也就是獲取到 IO讀寫事件之後,交由線程池來處理,Handler 收到響應後通過 send 將響應結果返回給客戶端。這樣可以降低 Reactor 的性能開銷,從而更專註的做事件分發工作瞭,提升整個應用的吞吐,並且 Handler 使用瞭多線程模式,可以充分利用 CPU 的性能。但是這個模型存在的問題:

(1)Handler 使用多線程模式,自然帶來瞭多線程競爭資源的開銷,同時涉及共享數據的互斥和保護機制,實現比較復雜

(2)單個 Reactor 承擔所有事件的監聽、分發和響應,對於高並發場景,容易造成性能瓶頸。

3、主從 Reactor 多線程模型:

        單Reactor多線程模型解決瞭 Handler 單線程的性能問題,但是 Reactor 還是單線程的,對於高並發場景還是會有性能瓶頸,所以需要將 Reactor 調整為多線程模式,也就是接下來要介紹的主從 Reactor 多線程模型。主從 Reactor 多線程模型將 Reactor 分成兩部分:

(1)MainReactor:隻負責處理連接建立事件,通過 select 監聽 server socket,將建立的 socketChannel 指定註冊給 subReactor,通常一個線程就可以瞭

(2)SubReactor:負責讀寫事件,維護自己的 selector,基於 MainReactor 註冊的 SocketChannel 進行多路分離 IO 讀寫事件,讀寫網絡數據,並將業務處理交由 worker 線程池來完成。SubReactor 的個數一般和 CPU 個數相同

3.1、處理流程: 

(1)主線程中的 MainReactor 對象通過 select 監聽事件,接收到事件後通過 Dispatch 進行分發,如果事件類型為連接建立事件則分發給 Acceptor 進行連接建立

連接建立:

① 從主線程池中隨機選擇一個 Reactor 線程作為 Acceptor 線程,用於綁定監聽端口,接收客戶端連接
② Acceptor 線程接收客戶端連接請求之後創建新的 SocketChannel,將其註冊到主線程池的其它 Reactor 線程上,由其負責接入認證、IP黑白名單過濾、握手等操作。
③ 步驟② 完成之後,業務層的鏈路正式建立,將 SocketChannel 從主線程池的 Reactor 線程的多路復用器上摘除,重新註冊到 SubReactor 線程池的線程上,並創建一個 Handler 用於處理各種連接事件

(2)如果接收到的不是連接建立事件,則分發給 SubReactor,SubReactor 調用當前連接對應的 Handler 進行處理

(3)Handler 通過 read 讀取數據後,將數據分發給 Worker 線程池進行業務處理,Worker 線程池則分配線程進行業務處理,完成後將響應結果發給 Handler

(4)Handler 收到響應結果後通過 send 將響應結果返回給 Client

3.2、優缺點:

        主從 Reactor 多線程模型的優點在於主線程和子線程分工明確,主線程隻負責接收新連接,子線程負責完成後續的業務處理,同時主線程和子線程的交互也很簡單,子線程接收主線程的連接後,隻管業務處理即可,無須關註主線程,可以直接在子線程將處理結果發送給客戶端。

        該 Reactor 模型適用於高並發場景,並且 Netty 網絡通信框架也是采用這種實現

4、Reactor 優缺點:

(1)響應快,不必為單個同步時間所阻塞,雖然 Reactor 本身依然是同步的;

(2)可以最大程度的避免復雜的多線程及同步問題,並且避免瞭多線程/進程的切換開銷

(3)可擴展性,可以方便地通過增加 Reactor 實例個數來充分利用 CPU 資源;

(4)可復用性,Reactor 模型本身與具體事件處理邏輯無關,具有很高的復用性。

Reacotr 模型是一種非阻塞同步網絡模型,除此之外,還有一種 Proactor 的異步網絡模型,對 Proactor 感興趣的讀者可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/122390285

參考文章:

徹底搞懂Reactor模型和Proactor模型 – 雲+社區 – 騰訊雲

【死磕 NIO】— Reactor 模式就一定意味著高性能嗎?

到此這篇關於Java IO篇之Reactor 網絡模型的概念的文章就介紹到這瞭,更多相關java Reactor 網絡模型內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: