--- tags: Research --- # Reactor vs Proactor ## Reactor I/O 事件加到 multiplexer 中輪詢,當 I/O 事件 ready,multiplexer 會將 I/O 事件送給註冊該事件的 Handler 處理。(有事先註冊事件對應的 Handler) * single Reactor and single-thread Reactor 模式主要由 Reactor 和處理資源池這兩個核心部分組成 * Reactor(dispatch) 負責監聽和分發事件,事件類型包含連接事件(派給 acceptor)、讀寫事件(派給 Handler) * Acceptor: 處理連接事件 * Handler: 處理 Read/Write I/O 事件,如 read -> 處理資料 -> send * single Reactor and multi-thread * Handler 不再處理資料,只負責做 Read/Write I/O 操作,Handler 對象通過 read 讀取到資料後,會將資料發給 thread pool 中的執行緒,這些執行緒負責處理資料,處理完後,將結果發給 main thread 中的 Handler,Handler 收到資料通過 send 將結果發送給 client。 單 Reactor 模式還有個問題,因為一個 Reactor 對象承擔所有事件的監聽和 response,而且只在 main thread 中運行,在面對瞬間高 concurrency 的場景時,容易遇到效能瓶頸。 * multi-Reactor and multi-thread * main thread 中的 MainReactor 通過 select 監聽 connection 事件,收到事件後通過 Acceptor 中的 accept 獲取連接,將新的連接分配給子執行緒。 * 子執行緒中的 SubReactor 將 MainReactor accept 後的 connection 加入 select 繼續進行監聽,並建立一個 Handler 用於處理 Read/Write I/O 操作。 * 如果有新的事件發生時,SubReactor 會呼叫對應的 Handler。 Handler 通過 read -> 處理資料 -> send 的流程來完成處理資料。 ## Proactor Hanlder 直接進行 asynchronous I/O 操作,將 asynchronous I/O 操作交由 kernel thread 處理,kernel thread 處理完成後會發 signal 通知 multiplexer,multiplexer 再通知 handler。 ## Conclusion * Reactor 是 non-blocking synchronous I/O 模式,透過就緒 (Ready) 可讀寫事件觸發。每次到有事件發生(比如可讀就緒事件)後,就需要 application 主動調用 read 方法來完成資料的讀取,也就是要 application 主動將 socket receiving buffer 中的資料讀到 application memory 中,這個過程是同步的,讀取完資料後才能進一步處理資料。 * Proactor 是 asynchronous I/O 模式,透過已完成的讀寫事件(kernel thread 已經讀到 userspace 的 buffer 中)觸發。在發起 asynchronous 讀寫請求時,需要傳入 userspace data buffer 的地址(用來存放結果資料),這樣 kernel thread 才可以自動幫我們把資料的讀寫工作完成,這裡的讀寫由作業系統來做,並不需要像 Reactor 那樣還需要主動發起 read/write 來讀寫資料,作業系統完成讀寫工作後,就會通知 application 直接處理資料。 ## 為什麼目前有很多 Server 應用的是 Reactor Design Pattern,而不是 Proactor ? * 問題是 AIO 並不能完整應用在所有的作業系統 * Windows 有比較完整的 AIO interface `IOCP` * MacOS 目前沒有相關介面 * Linux 有一套 native async IO interface,但仍然有一些缺點,不過後來有出現 io_uring 這個介面,但是 io_uring 是 2019 年 Linux 5.1 才引入的 ### Linux native async IO 缺點 1. 必須設定為 `O_DIRECT` * Open 的時候通過 flag 來指定 `O_DIRECT` 參數,之後資料的 write/read 操作都是繞過 OS 維護的 page cache,直接對 disk 做 I/O 操作,但不支援對於 network sockets 的 I/O 操作 * 普遍情況下,這樣的設定會影響效能 2. Linux AIO 雖然是 Asynchronous 的,但可能會 block ## TODO: io_uring ## Reference * https://www.zhihu.com/question/26943938 * https://arthurchiao.art/blog/intro-to-io-uring-zh/