單Reactor多線程
網絡模型圖:
圖片來源:https://blog.csdn.net/weixin_43326401/article/details/104202424
消息處理流程:
- Reactor對象通過epoll監控連接事件,收到事件后通過回調函數進行轉發。
- 如果是連接建立的事件,則由acceptor接受連接,並創建handler處理后續事件。
- 如果不是建立連接事件,如read事件,則Reactor會分發調用Handler來響應。
- handler會完成read->業務處理->send的完整業務流程。
單Reactor單線程模型只是在代碼上進行了組件的區分,但是整體操作還是單線程,不能充分利用硬件資源。handler業務處理部分沒有異步。
對於一些小容量應用場景,可以使用單Reactor單線程模型。但是對於高負載、大並發的應用場景卻不合適,主要原因如下:
- 即便Reactor線程的CPU負荷達到100%,也無法滿足海量消息的編碼、解碼、讀取和發送。
- 當Reactor線程負載過重之后,處理速度將變慢,這會導致大量客戶端連接超時,超時之后往往會進行重發,這更加重Reactor線程的負載,最終會導致大量消息積壓和處理超時,成為系統的性能瓶頸。
- 一旦Reactor線程意外中斷或者進入死循環,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障。
為了解決這些問題,演進出單Reactor多線程模型。
主 - 從Reactor多線程
主 - 從 reactor 模式
下面的這張圖描述了主 - 從 reactor 模式是如何工作的。主 - 從這個模式的核心思想是,主反應堆線程只負責分發 Acceptor 連接建立,已連接套接字上的 I/O 事件交給 sub-reactor 負責分發。其中 sub-reactor 的數量,可以根據 CPU 的核數來靈活設置。
比如一個四核 CPU,我們可以設置 sub-reactor 為 4。相當於有 4 個身手不凡的反應堆線程同時在工作,這大大增強了 I/O 分發處理的效率。而且,同一個套接字事件分發只會出現在一個反應堆線程中,這會大大減少並發處理的鎖開銷。

主反應堆線程一直在感知連接建立的事件,如果有連接成功建立,主反應堆線程通過 accept 方法獲取已連接套接字,接下來會按照一定的算法選取一個從反應堆線程,並把已連接套接字加入到選擇好的從反應堆線程中。
主反應堆線程唯一的工作,就是調用 accept 獲取已連接套接字,以及將已連接套接字加入到從反應堆線程中。不過,這里還有一個小問題,主反應堆線程和從反應堆線程,是兩個不同的線程,如何把已連接套接字加入到另外一個線程中呢?更令人沮喪的是,此時從反應堆線程或許處於事件分發的無限循環之中,在這種情況下應該怎么辦呢?
推出主 - 從Reactor多線程
如果說主 - 從 reactor 模式解決了 I/O 分發的高效率問題,那么 work threads 就解決了業務邏輯和 I/O 分發之間的耦合問題。把這兩個策略組裝在一起,就是實戰中普遍采用的模式。大名鼎鼎的 Netty,就是把這種模式發揮到極致的一種實現。