Reactor 模式
wiki: “The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.”
為什麼會有 Reactor 呢
對於應用程式而言,CPU 的處理速度是遠遠快於 IO 的速度的。如果CPU為了IO操作(例如從Socket讀取一段資料)而阻塞顯然是不划算的。好一點的方法是分為多程序或者執行緒去進行處理,但是這樣會帶來一些程序切換的開銷,試想一個程序一個數據讀了500ms,期間程序切換到它3次,但是CPU卻什麼都不能幹,就這麼切換走了,是不是也不划算?
這時先驅們找到了事件驅動,或者叫回調的方式,來完成這件事情。這種方式就是,應用業務向一箇中間人註冊一個回撥(event handler),當IO就緒後,就這個中間人產生一個事件,並通知此handler進行處理。這種回撥的方式,也體現了“好萊塢原則”(Hollywood principle)-“Don’t call us, we’ll call you”,在我們熟悉的IoC中也有用到。看來軟體開發真是互通的!
Reactor 應用場景
Reactor 核心是解決多請求問題。一般來說,Thread-Per-Connection 的應用場景併發量不是特別大,如果併發量過大,會導致執行緒資源瞬間耗盡,導致服務陷入阻塞,這個時候就需要 Reactor 模式來解決這個問題。Reactor 通過多路複用的思想大大減少執行緒資源的使用。
Reactor 結構

上圖是 Reactor 模型,主要涉及的類:
Initiation Dispatcher Even Handler Handle Synchronous Event Demultiplexer
Reactor 時序圖

- 初始化 InitationDispatcher,並初始化一個Handle到EventHandler的Map。
- 註冊 EvenHandler 到 InitationDispatcher,每個 EventHandler 包含對相應 Handle 的引用,從而建立Handle到EventHandler的對映(Map)。
- 呼叫 InitiationDispatcher 的 handle_events() 方法以啟動 Event Loop。在 Event Loop 中,呼叫 select()方法(Synchronous Event Demultiplexer)阻塞等待Event發生。
- 當某個或某些 Handle 的 Event 發生後,select() 方法返回,InitiationDispatcher 根據返回的Handle找到註冊的 EventHandler ,並回調該 EventHandler 的 handle_events() 方法。
- 在 EventHandler 的 handle_events() 方法中還可以向 InitiationDispatcher 中註冊新的 Eventhandler,比如對 AcceptorEventHandler 來說,當有新的 client 連線時,它會產生新的 EventHandler 以處理新的連線,並註冊到 InitiationDispatcher 中。
Reactor 模式
單執行緒 Reactor 模式

簡單來說,接收請求和處理請求是同一執行緒中處理。
對於一些小容量應用場景,可以使用單執行緒模型。但是對於高負載、大併發或大資料量的應用場景卻不合適,主要原因如下: ① 一個NIO執行緒同時處理成百上千的鏈路,效能上無法支撐,即便NIO執行緒的CPU負荷達到100%,也無法滿足海量訊息的讀取和傳送; ② 當NIO執行緒負載過重之後,處理速度將變慢,這會導致大量客戶端連線超時,超時之後往往會進行重發,這更加重了NIO執行緒的負載,最終會導致大量訊息積壓和處理超時,成為系統的效能瓶頸;
多執行緒 Reactor 模式

簡單來說,接收請求和處理請求是不同執行緒中處理。
mainReactor 一般只有一個,主要負責接收客戶端的連線並將其傳遞給 subReactor。subReactor 一般會有多個,主要負責處理與客戶端的通訊。
注意:上圖使用了 Thread Pool
來處理耗時的業務邏輯,提高Reactor執行緒的I/O響應,不至於因為一些耗時的業務邏輯而延遲對後面I/O請求的處理。