您好,登錄后才能下訂單哦!
小編給大家分享一下Java IO中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 可以是單個也可以是多個,Handler 同樣可以是單線程也可以是多線程,所以組合的模式大致有如下三種:
單 Reactor 單線程模型
單 Reactor 多線程模型
主從 Reactor 單線程模型
主從 Reactor 多線程模型
其中第三種的主從Reactor單線程模型沒什么實際意義,所以下文就著重介紹其他三種模型
(1)Reactor 線程通過 select 監聽事件,收到事件后通過 Dispatch 進行分發
(2)如果是連接建立事件,則將事件分發給 Acceptor,Acceptor 會通過 accept() 方法獲取連接,并創建一個Handler 對象來處理后續的響應事件
(3)如果是IO讀寫事件,則 Reactor 會將該事件交由當前連接的 Handler 來處理
(4)Handler 會完成 read -> 業務處理 -> send 的完整業務流程
單 Reactor 單線程模型的優點在于將所有處理邏輯放在一個線程中實現,沒有多線程、進程通信、競爭的問題。但該模型在性能與可靠性方面存在比較嚴重的問題:
① 性能:只在代碼上進行組件的區分,整體操作還是單線程,無法充分利用 CPU 資源,并且 Handler 業務處理部分沒有異步,一個 Reactor 既要負責處理連接請求,又要負責處理讀寫請求,一般來說處理連接請求是很快的,但處理讀寫請求時涉及到業務邏輯處理,相對慢很多。所以 Reactor 在處理讀寫請求時,其他請求只能等著,容易造成系統的性能瓶頸
② 可靠性:一旦 Reactor 線程意外中斷或者進入死循環,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障
所以該單Reactor單進程模型不適用于計算密集型的場景,只適用于業務處理非常快速的場景。Redis的線程模型就是基于單 Reactor 單線程模型實現的,因為 Redis 業務處理主要是在內存中完成,操作的速度是很快的,性能瓶頸不在 CPU 上,所以 Redis 對于命令的處理是單進程的。
為了解決單Reactor單線程模型存在的性能問題,就演進出了單 Reactor 多線程模型,該模型在事件處理器部分采用了多線程(線程池)
(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。
相對于第一種模型來說,在處理業務邏輯,也就是獲取到 IO讀寫事件之后,交由線程池來處理,Handler 收到響應后通過 send 將響應結果返回給客戶端。這樣可以降低 Reactor 的性能開銷,從而更專注的做事件分發工作了,提升整個應用的吞吐,并且 Handler 使用了多線程模式,可以充分利用 CPU 的性能。但是這個模型存在的問題:
(1)Handler 使用多線程模式,自然帶來了多線程競爭資源的開銷,同時涉及共享數據的互斥和保護機制,實現比較復雜
(2)單個 Reactor 承擔所有事件的監聽、分發和響應,對于高并發場景,容易造成性能瓶頸。
單Reactor多線程模型解決了 Handler 單線程的性能問題,但是 Reactor 還是單線程的,對于高并發場景還是會有性能瓶頸,所以需要將 Reactor 調整為多線程模式,也就是接下來要介紹的主從 Reactor 多線程模型。主從 Reactor 多線程模型將 Reactor 分成兩部分:
(1)MainReactor:只負責處理連接建立事件,通過 select 監聽 server socket,將建立的 socketChannel 指定注冊給 subReactor,通常一個線程就可以了
(2)SubReactor:負責讀寫事件,維護自己的 selector,基于 MainReactor 注冊的 SocketChannel 進行多路分離 IO 讀寫事件,讀寫網絡數據,并將業務處理交由 worker 線程池來完成。SubReactor 的個數一般和 CPU 個數相同
(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
主從 Reactor 多線程模型的優點在于主線程和子線程分工明確,主線程只負責接收新連接,子線程負責完成后續的業務處理,同時主線程和子線程的交互也很簡單,子線程接收主線程的連接后,只管業務處理即可,無須關注主線程,可以直接在子線程將處理結果發送給客戶端。
該 Reactor 模型適用于高并發場景,并且 Netty 網絡通信框架也是采用這種實現
(1)響應快,不必為單個同步時間所阻塞,雖然 Reactor 本身依然是同步的;
(2)可以最大程度的避免復雜的多線程及同步問題,并且避免了多線程/進程的切換開銷
(3)可擴展性,可以方便地通過增加 Reactor 實例個數來充分利用 CPU 資源;
(4)可復用性,Reactor 模型本身與具體事件處理邏輯無關,具有很高的復用性。
以上是“Java IO中Reactor網絡模型的概念是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。