Reactor線程模型詳解
簡介
一、單Reactor單線程
二、單Reactor多線程
三、主從Reactor多線程
簡介
在目前的線程模型中一種是傳統阻塞的I/O模型,一種是Reactor線程模型。Reactor模型根據Reactor的數量和處理資源線程池的數量不同又分為三種Reactor線程模型:
- 單Reactor單線程
- 單Reactor多線程
- 主從Reactor多線
Reactor模型的核心是:Reactor+Handles。Reactor在一個單獨的線程中運行,負責監聽和分發事件,將接收到的io事件交給不同的Handle來處理響應。Handles是處理程序執行I/O事件的實際操作,Reactor通過調度適當的Handles來處理io事件。
目前常用的Netty、Redis、Memcached、Nignx都是基於Reactor模式實現的。
其下面我們分別介紹這幾種線程模型。
一、單Reactor單線程
原理圖:
流程:
1. Reactor 對象通過 Select 監控客戶端請求事件,收到事件后通過 Dispatch 進行分發。
2. 如果是建立連接請求事件,則由 Acceptor 通過 Accept 處理連接請求,然后創建一個 Handler 對象處理連接完成后的后續業務處理。
3. 如果不是建立連接事件,則 Reactor 會分發調用連接對應的 Handler 來響應
4. Handler 會完成 Read→業務處理→Send 的完整業務流程。
優點:
模型簡單,沒有多線程、進程通信、競爭的問題,全部都在一個線程中完成。
缺點:
1. 性能問題,只有一個線程,無法完全發揮多核 CPU 的性能。Handler 在處理某個連接上的業務時,整個進程無法處理其他連接事件,很容易導致性能阻塞。
2. 可靠性問題,線程意外終止,或者進入死循環,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障。
使用場景:
客戶端的數量有限,業務處理非常快速。java原生nio就是這個模型。
二、單Reactor多線程
原理圖:
流程:
1. Reactor 對象通過select 監控客戶端請求事件, 收到事件后,通過dispatch進行分發。
2. 如果建立連接請求, 則由Acceptor 通過accept 處理連接請求, 然后創建一個Handler對象處理完成連接后的各種事件。
3. 如果不是連接請求,則由reactor分發調用連接對應的handler 來處理。
4. handler 只負責響應事件,不做具體的業務處理, 通過read 讀取數據后,會分發給后面的worker線程池的某個線程處理業務。
5. worker 線程池會分配獨立線程完成真正的業務,並將結果返回給handler。
6. handler收到響應后,通過send 將結果返回給client。
優點:
可以充分的利用多核cpu 的處理能力。
缺點:
多線程數據共享和訪問比較復雜, reactor 處理所有的事件的監聽和響應,在單線程運行, 在高並發場景容易出現性能瓶頸.。
三、主從Reactor多線程
原理圖:
流程:
1. Reactor主線程 MainReactor 對象通過select 監聽連接事件, 收到事件后,通過Acceptor 處理連接事件。
2. 當 Acceptor 處理連接事件后,MainReactor 將連接分配給SubReactor 。
3. subreactor 將連接加入到連接隊列進行監聽,並創建handler進行各種事件處理。
4. 當有新事件發生時, subreactor 就會調用對應的handler處理。
5. handler 通過read 讀取數據,分發給后面的worker 線程處理。
6. worker 線程池分配獨立的worker 線程進行業務處理,並返回結果。
7. handler 收到響應的結果后,再通過send 將結果返回給client。
8. Reactor 主線程可以對應多個Reactor 子線程, 即MainRecator 可以關聯多個SubReactor。
優點:
1. 父線程與子線程的數據交互簡單職責明確,父線程只需要接收新連接,子線程完成后續的業務處理。
2. 父線程與子線程的數據交互簡單,Reactor 主線程只需要把新連接傳給子線程,子線程無需返回數據。
缺點:
編程復雜度較高。
應用場景:
這種模型在許多項目中廣泛使用,包括 Nginx 主從 Reactor 多進程模型,Memcached 主從多線程,Netty 主從多線程模型的支持。