swoole的進程/線程結構
結構圖如下:
swoole主要由Master進程(主進程)和Manager進程配合使用完成其功能。
Master進程
是一個多線程的程序。其中有一組很重要的線程,稱之為Reactor線程。它就是真正處理TCP連接,收發數據的線程。
Manager進程
管理worker/task進程。worker/task進程都是由Manager進程Fork並管理的。
Reactor線程
主線程(Master進程)在Accept新的連接后,會將這個連接分配給一個固定的Reactor線程,並由這個線程負責監聽此socket。在socket可讀時讀取數據,並進行協議解析,將請求投遞到Worker進程。
- 負責維護客戶端
TCP
連接、處理網絡IO
、處理協議、收發數據 - 完全是異步非阻塞的模式
- 全部為
C
代碼,除Start
/Shudown
事件回調外,不執行任何PHP代碼 - 將
TCP
客戶端發來的數據緩沖、拼接、拆分成完整的一個請求數據包 Reactor
以多線程的方式運行
Work進程
類似與php-fpm進程。
- 接受由
Reactor
線程投遞的請求數據包,並執行PHP
回調函數處理數據 - 生成響應數據並發給
Reactor
線程,由Reactor
線程發送給TCP
客戶端 - 可以是異步模式,也可以是同步模式
Worker
以多進程的方式運行
TaskWorker進程
異步處理其他任務的進程,使用方方式類似與Gearman。
- 接受由
Worker
進程通過swoole_server->task/taskwait
方法投遞的任務 - 處理任務,並將結果數據返回(
swoole_server->finish
)給Worker
進程 TaskWorker
以多進程的方式運行
關系
可以理解為Reactor
就是nginx
,Worker
就是php-fpm
。Reactor
線程異步並行地處理網絡請求,然后再轉發給Worker
進程中去處理(在回調函數中處理)。Reactor
和Worker
間通過UnixSocket
進行通信。
事件處理流程
了解swoole事件處理流程,先了解兩種網絡事件處理模式。
Reactor模式
它要求主線程(I/O處理單元)只負責監聽文件描述符上是否有事件發生,有的話就立即將該事件通知工作線程/進程(邏輯單元)。除此之外,主線程不做任何其他工作。讀寫數據,接受新的連接,以及處理客戶請求均在工作線程中完成。
Proactor模式
兩種實現
使用I/O異步模型實現Proactor模式。原理:將所有I/O操作都交給主線程,主線程配合和內核來處理,業務邏輯操作就交給邏輯單元。例如使用aio_read來實現。
工作流程:
- 主線程調用aio_read函數向內核注冊socket上的讀完成事件。
- 主線程繼續處理其他I/O事件。
- 當socket上的數據被讀入用戶緩沖區后,內核向應用程序(邏輯單元)發送一個信號,通知應用程序數據可用。
- 應用程序讀取數據(客戶端的請求),處理完后,調用aio_write函數向內核注冊socket上的寫事件。
- 主線程繼續處理其他邏輯。
- 當用戶緩沖區的數據寫入socket后,內核向應用程序發送一個信號,通知應用程序數據發送完畢。
- 應用程序預先定義好的信號處理函數來處理善后處理,比如關閉socket.
使用I/O同步模型實現Proactor模式。原理:主線程執行I/O事件數據的讀寫操作,業務邏輯操作就交給邏輯單元。例如使用epoll來實現。
工作流程:
- 主線程往epoll內核事件表中注冊socket上的讀就緒事件。
- 主線程調用epoll_wait等待socket上有數據可讀。
- epoll_wait有返回后,主線程從socket上讀取數據,然后將讀取到的數據封裝成一個請求對象(客戶端的請求),並插入請求隊列。
- 於是隊列的消費者線程處理請求對象,然后在epoll內核事件表中注冊socket上的寫就緒事件。
- 主線程調用epoll_wait等待socket可寫。
- 當socket可寫時,epoll_wait通知主線程。主線程往socket寫入請求結果。
swoole事件架構圖
從圖可以看出,如果我們把Reactor線程和Work進程組合起來,看成工作線程的話,swoole使用的是reactor事件處理模式。
一個請求經歷的步驟如下:
1. 服務器主線程等待客戶端連接。
2. Reactor線程處理接連socket,讀取socket上的請求數據(Receive),將請求封裝好后投遞給work進程。
3. Work進程就是邏輯單元,處理業務數據。
4. Work進程結果返回給Reactor線程。
5. Reactor線程將結果寫回socket(Send)。
每個模塊的工作請回顧上面的結構介紹。