在高效能網路技術中,大家應該經常會看到Reactor模型。並且很多開源軟體中都使用了這個模型,如:Redis、Nginx、Memcache、Netty等。
剛開始接觸時可能一頭霧水,這到底是個什麼東東?一查英文解釋:“反應堆”,感覺更加唬人了。那麼,今天我們來一起看看這個Reactor到底是個啥。
其實通俗點講,Reacotr = IO多路複用 + 池化技術。是“大神”們將IO多路複用技術結池化技術(執行緒池程式池)結合的一種模式。IO多路服用負責統一監聽事件,收到事件後派發給資源池中的某個執行緒或程式。
其中根據Reacotr的數量和資源池中資源的數量和型別,Reactor有以下3種典型實現方案。其中“多Reactor單程式/執行緒”實現方案相比“單 Reactor 單程式”方案,既複雜又沒有效能優勢,因此實際沒有應用。
- 單Reactor + 單程式/單執行緒
- 單Reactor + 多執行緒
- 多Reactor + 多程式/多執行緒
下面我們逐一介紹一下這3個方案,及他們適用的場景。
單Reactor + 單程式/單執行緒
該方案示意圖如下(以程式舉例):
Reactor 物件通過 select 監控連線事件,收到事件後通過 dispatch 進行分發。
如果是連線建立的事件,則由 Acceptor 處理,Acceptor 通過 accept 接受連線,並建立一個 Handler 來處理連線後續的各種事件。
如果不是連線建立事件,則 Reactor 會呼叫連線對應的 Handler(第 2 步中建立的Handler)來進行響應。Handler 會完成 read-> 處理 ->send 的完整業務流程。
這種優點很明顯,就是簡單,不用考慮程式間通訊、執行緒安全、資源競爭等問題。但是也有自身的侷限性,就是無法利用多核資源,只適用於業務處理非常快速的場景,Redis就是採用的這種方案。
單Reactor + 多執行緒
該方案示意圖如下:
與第一種方案相比,不同的是:Handler只負責響應事件,並不負責處理事件,Handler讀取資料後會傳送給Processor進行處理。Processor在子執行緒中完成業務處理,然後將結果傳送給Handler。由Handler將結果返回給client。
你可能主要到沒有列出單Reactor + 多程式方案,主要因為如果採用多程式,就要考慮程式間通訊的問題,比如子程式處理完成後需要通知父程式將結果返回給對應的client,處理比較複雜。但多執行緒之間資料是共享的,複雜度相對比較低。
另外,這種方案下,主執行緒承擔了所有的事件監聽和響應。瞬間高併發時可能會成為效能瓶頸。這時就需要多Reactor的方案了。
多Reactor + 多程式/多執行緒
該方案示意圖如下(以程式舉例):
父程式中 mainReactor 物件通過 select 監控連線建立事件,收到事件後通過 Acceptor接收,將新的連線分配給某個子程式。
子程式的 subReactor 將 mainReactor 分配的連線加入連線佇列進行監聽,並建立一個Handler 用於處理連線的各種事件。
當有新的事件發生時,subReactor 會呼叫連線對應的 Handler(即第 2 步中建立的Handler)來進行響應。
Handler 完成 read→處理→send 的完整業務流程。
目前著名的開源系統 Nginx 採用的是多 Reactor 多程式,採用多 Reactor 多執行緒的實現有Memcache 和 Netty。不過需要注意的是 Nginx 中與上圖中的方案稍有差異,具體表現在主程式中並沒有mainReactor來建立連線,而是由子程式中的subReactor建立。
Proactor模式
以上就是Reactor模式中的幾種常見方案,另外除了Reactor模式還有Proactor模式。Reactor 是非阻塞同步網路模型,因為真正的 read 和 send 操作都需要使用者程式同步操作。這裡的“同步”指使用者程式在執行 read 和 send 這類 I/O 操作的時候是同步的,如果把 I/O 操作改為非同步就能夠進一步提升效能,這就是非同步網路模型 Proactor。
理論上 Proactor 比 Reactor 效率要高一些,但在 Linux 系統下的非同步並不完善,因此在 Linux 下實現高併發網路程式設計時都是以 Reactor 模式為主。所以今天就不對 Proactor 模式進行過多介紹了。
參考資料
- https://time.geekbang.org/column/article/8805
如果以上對你有幫助,歡迎關注鐵柱,一起成長。