Reactor pattern
看這篇 paper。
問題 & 情境
Reactor pattern 處理一個 application 收到從一個或多個 client 同時(concurrently)送 request 的情況。
分散式環境的 server 必須處理多個送 request 過來的 client。為了處理 request,server 必須 demultiplex 以及 dispatch request 給對應的 service。設計 demultiplexing 及 dispatching 需考量:
- Availability
server 在等待某些 request 時(例如 server 與 client 間需要多步驟溝通,server 正在等 client 的某個步驟),server 依然能處理收到的 request,不能因為處理某個 request 而 block 住,不然會卡到對其他 request 的 response。 - Efficiency
server 要最小化 latency、最大化 throughput 以及避免不必要的 CPU 使用。 - Programming simplicity
顧名思義,程式寫得愈簡單愈好。 - Adaptability
容易新增或改進 service,修改最少現有的 code 就能加新功能或改進功能,例如新增 service 不用修改底層的 dispatching 機制。 - Portability
容易 porting 到其他 OS 平台等。
Solution
整合 demultiplexing 以及 dispatching 並且 decouple 通用的 event demultiplexing & dispatching 以及處理 request 的 service 實作邏輯、屬於應用邏輯的部份。讓 dispatch 歸 dispatch,應用邏輯歸應用邏輯,兩邊別混在一起。
Structure
看圖說故事比較容易,圖片出處。
- Handle
- 代表由 OS 管理的 resource,例如 network、file 等 resource。
- 像 Linux 用 file descriptor 代表 file、socket 等等,Windows 用各種 handle 代表 resource。
- Synchronous Event Demultiplexer
- 負責看一堆 handle 有沒有人有 event、可以動作了。
- 如果沒人可以動會 block 住,有人可以動時會 return,例如處理 IO event 的
select()
。
- Initiation Dispatcher
- 提供 register、remove event handler 以及 dispatch event 的介面。
- Synchronous Event Demultiplexer 收到 event 時會通知 Initiation Dispatcher,Initiation Dispatcher dispatch event 給處理的 event handler。
- Event Handler
- 定義 event handler 的介面。
- Concrete Event Handler
- 繼承 Event Handler,實際實作處理 event 的邏輯。
流程
- application 向 Initiation Dispatcher 註冊 Concrete Event Handler,告訴 Initiation Dispatcher 這個 handler 處理哪種 event。
- application call Initiation Dispatcher 的
handle_events()
進入 event loop。Initiation Dispatcher 由 Event Handler 取得 Handle 交給 Synchronous Event Demultiplexer 等待 event。 - event 發生時 Synchronous Event Demultiplexer 通知 Initiation Dispatcher(以
select()
來說是 return)。 - Initiation Dispatcher call 對應 Event Handler 的 function 來處理 event。
優缺點
優點
- decouple 了 application 功能上的實作邏輯以及與 application 無關的 demultiplexing & dispatching 機制,各自負責各自的事。
- 區分多個 service、各 service 負責自己相關的事情,讓 event-driven application 有較好的模組化並且能重複使用模組。
- 增加 portability。Initiation Dispatcher 的 interface 不受限於特定 OS,可在不同的 demultiplexing system call 重複使用。
- Initiation Dispatcher 的 event loop 依序 call event handler 減少複雜的 synchronization 機制。
缺點
- 只在有提供 Handle 的 OS 上有效率。
- non-preemptive:single thread application 中 Event Handler 執行時是無法被中斷、改去做其他事的,所以 Event Handler 處理 event 時不能被 block 住,不然整個 process 就卡住了。所以需要較長時間處理 event 的 application 不適合 reactor pattern。
- reactor pattern 會用在 framework 裡,導致 control flow 在 application 的 handler 及 framework 間跳來跳去,對於寫 application 、不熟悉 framework 運作或者根本看不到 framework 的 code 的開發者較難以 debug。
實作細節
流程上雖然一開始就向 Dispatcher 註冊完 event handler,但也可能是某種 event handler 處理 event 時才生另外的 event handler 並且註冊,即註冊及移除 event handler 是動態的。例如 Linux 處理 accept socket connection 的 event handler 在 accept()
後才生處理 client request 的 event handler 並向 Dispatcher 註冊,之後由該 event handler 處理 client 的 request。