004——Netty之高效能IO(Reactor)
阿新 • • 發佈:2018-11-25
一、原始方式
方法一:
# 使用while迴圈,不斷監聽埠是否有新的套接字連結
while(true){
socket = accept();
handle(socket)
}
# 做法侷限:處理效率低下,併發是請求只能阻塞
方法二:
# 一個連線對應一個執行緒
while(true){
socket = accept();
new thread(socket);
}
# 每個執行緒阻塞不會影響到後續請求,但對資源要求非常高。執行緒粒度大,每個執行緒一次性處理所有互動事情(連線、讀取和寫入),限制了吞吐量。
方法三:
# 將執行緒粒度減小。將一次連線的操作劃分為更細的粒度或者過程。這樣雖然執行緒數量變多,但是處理的事情更為簡單和單一
二、Reactor定義
關鍵點
事件驅動(event handling)
可以處理一個或多個輸入源(one or more inputs)
通過Service Handler同步的將輸入事件(Event)採用多路複用分發給對應Handler處理
處理流程
- 同步的等待多個事件源到達(採用select()實現)
- 將事件多路分解以及分配相應的事件服務進行處理,這個分派採用server集中處理(dispatch)
- 分解的事件以及對應的事件服務應用從分派服務中分離出去(handler)
使用Reactor的原因
NIO的優點:
- 基於事件驅動(selector支援對多個Channel進行監聽)
- 統一事件處理分派中心(dispatch)
- 事件處理服務
不足
- 更少的開銷,更少的上下文切換以及locking
- 能夠跟蹤伺服器狀態
- 能夠管理handler 對event的繫結
三、Reactor模式
介紹
Reactor將被拆分的子過程對應到Handler上,每一種handler會處理一種event。Selector全域性管理進行全域性管理。我們只需要註冊感興趣的channel事件,selector就會通過輪詢的方式不斷檢測channel上的事件是否發生。如果沒有事件發生則執行緒阻塞,如果時間發生,則呼叫相應handler進行處理。
非Reactor模型
- 這種模型由於IO在阻塞時會一直等待,因此在使用者負載增加時,效能下降的非常快
- serversocket的accept方法,阻塞等待client連線,直到client連線成功
- 執行緒從socket inputstream讀入資料,會進入阻塞狀態,直到全部資料讀完
- 執行緒向socket outputstream寫入資料,會阻塞直到全部資料寫完
Reactor模型
- Reactor 將I/O事件分派給對應的Handler
- Acceptor 處理客戶端新連線,並分派請求到處理器鏈中
- Handlers 執行非阻塞讀/寫任務,Event繫結
單Reactor單執行緒模型
改進點:基於事件模式,當事件觸發時,才呼叫處理器進行處理
- 當新連線到來觸發connect事件之後,交由Acceptor進行處理,並構造Handler
- 有IO讀寫事件之後交給Hanlder處理。
- 在獲取到Client相關的SocketChannel之後,繫結到相應Handler上。
- 若是連線事件獲取是acceptor,若是IO讀寫事件獲取是handler。都由Reactor進行分發
Acceptor主要任務就是構建handler ,在獲取到和client相關的SocketChannel之後 ,繫結到相應的hanlder上,對應的SocketChannel有讀寫事件之後,基於racotor 分發,hanlder就可以處理了(所有的IO事件都繫結到selector上,有Reactor分發)。
單Reactor多執行緒模型
改進:使用多執行緒處理業務邏輯。
- 專門一個IO執行緒——Acceptor執行緒負責監聽服務端請求。
- 訊息讀取、解碼、編碼、傳送由執行緒池負責
- 一個鏈路只對應一個執行緒,可以避免同步操作。
- Reacpter只負責訊息分發
多Reactor多執行緒模型
- mainReactor負責監聽 ServerSocketChannel ,用來處理客戶端新連線的建立,並將建立的客戶端的SocketChannel指定註冊給 subReactor 。
- subReactor 維護自己的 Selector ,基於 mainReactor 建立的客戶端的 SocketChannel 多路分離 IO 讀寫事件,讀寫網路資料。對於業務處理的功能,另外扔給 worker 執行緒池來完成。
- 該模式為Netty預設模式