編程學習網 > PHP技術 > swoole > swoole進程模型詳解
2021
08-12

swoole進程模型詳解

在軟件開發中,最常見的并發問題解決方案,莫過于多線程/多進程兩種模式了。在《計算機組成原理》中我們都學過,并發中最迫切需要解決的問題之一,就是數據的可靠性問題,而不同的并發模型,其并發數據可靠性的機制往往各有特點,因此,在使用swoole Server\Client的過程中,其并發解決方案的模型是必須要了解的,否則使用上很容易出現不符合預期的結果。

Swoole目前總共有三種運行模式,其中Base模式基本沒有生產應用價值;協程模式暫時還處于預覽階段;因此,筆者在此想和大家討論的,就是Swoole的多進程模式,也是官方目前最推薦用于生產環境的模式。事實上,Swoole曾經還有多線程模式,但由于Zend在多線程模式本身的缺陷,在1.6版本后,多線程模式已經被關閉。

首先,我們還是先來簡單了解一下Swoole Server的構造函數,是一個參數的問題:


<?php

$server = new \swoole_server("127.0.0.1",8088,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);


第三個參數mode中我們填入的PROCESS,即表示當前Server是運行于多進程模式的。其他mode的可選參數可以參考手冊

然后,我們簡單實現一個沒有任何內容的Server:


<?php

$server = new \swoole_server("127.0.0.1",8088,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);

$server->on('connect', function ($serv, $fd){ });

$server->on('receive', function ($serv, $fd, $from_id, $data){ });

$server->on('close', function ($serv, $fd){ });

$server -> start();


在啟動服務之后,我們繼續在Shell中輸入以下命令:


> php swoole_server_demo.php

> pstree -ap|grep swoole_server_demo

 |-php,2829 swoole_server_demo.php

 |   |-php,2831 swoole_server_demo.php

 |   |   `-php,2836 swoole_server_demo.php


pstree命令可以查看進程的樹模型

從系統的輸出中,我們可以很容看出server其實有3個進程,進程的pid分別是2829、2831、2836,其中2829是2831的父進程,而2831又是2836的父進程。所以,其實我們雖然看起來只是啟動了一個Server,其實最后產生的是三個進程。這三個進程中,所有進程的根進程,也就是例子中的2829進程,就是所謂的Master進程;而2831進程,則是Manager進程;最后的2836進程,是Worker進程。基于此,我們簡單梳理一下,當執行的start方法之后,發生了什么:


  • 守護進程模式下,當前進程fork出Master進程,然后退出,Master進程觸發OnMasterStart事件。
  • Master進程啟動成功之后,fork出Manager進程,并觸發OnManagerStart事件。
  • Manager進程啟動成功時候,fork出Worker進程,并觸發OnWorkerStart事件。


非守護進程模式下,則當前進程直接作為Master進程工作。


所以,一個最基礎的Swoole Server,至少需要有3個進程,分別是Master進程、Manager進程和Worker進程。不要看到進程多就覺得麻煩咯,其實全賴它們各司其職,才有Swoole重新定義PHP的壯舉。事實上,一個多進程模式下的Swoole Server中,有且只有一個Master進程;有且只有一個Manager進程;卻可以有n個Worker進程。那么這幾個進程之間是怎么協同工作的呢?我們先暫時考慮只有一個Worker的情況。那么,我們又可以拉出之前寫的最簡單Server,來看看這個過程中,三種進程之間是怎么協作的。Client主動Connect的時候,Client實際上是與Master進程中的某個Reactor線程發生了連接。

當TCP的三次握手成功了以后,由這個Reactor線程將連接成功的消息告訴Manager進程,再由Manager進程轉交給Worker進程。在這個Worker進程中觸發了OnConnect的方法。

當Client向Server發送了一個數據包的時候,首先收到數據包的是Reactor線程,同時Reactor線程會完成組包,再將組好的包交給Manager進程,由Manager進程轉交給Worker。此時Worker進程觸發OnReceive事件。如果在Worker進程中做了什么處理,然后再用Send方法將數據發回給客戶端時,數據則會沿著這個路徑逆流而上。

同樣的故事,隨著認識的加深,會發現不一樣的精彩

首先,Master進程是一個多線程進程,其中有一組非常重要的線程,叫做Reactor線程(組),每當一個客戶端連接上服務器的時候,都會由Master進程從已有的Reactor線程中,根據一定規則挑選一個,專門負責向這個客戶端提供維持鏈接、處理網絡IO與收發數據等服務。以前我們提到的分包拆包等功能也是在這里完成的哦。而Manager進程,某種意義上可以看做一個代理層,它本身并不直接處理業務,其主要工作是將Master進程中收到的數據轉交給Worker進程,或者將Worker進程中希望發給客戶端的數據轉交給Master進程進行發送。另外,Manager進程還負責監控Worker進程,如果Worker進程因為某些意外掛了,Manager進程會重新拉起新的Worker進程,有點像Supervisor的工作,而這個特性,也是最終實現熱重載的核心機制。

最后就是Worker進程了,顧名思義,Worker進程其實就是處理各種業務工作的進程,Manager將數據包轉交給Worker進程,然后Worker進程進行具體的處理,并根據實際情況將結果反饋給客戶端。

如果要打個比方的話,Master進程就像業務窗口的,Reactor就是前臺接待員,用戶很多的時候,后邊的用戶就需要排隊等待服務;Reactor負責與客戶直接溝通,對客戶的請求進行初步的整理(傳輸層級別的整理——組包);然后,Manager進程就是類似項目經理的角色,要負責將業務分配給合適的Worker(例如空閑的Worker);而Worker進程就是工人,負責實現具體的業務。

實際上,一對多投遞這種模式總是在并發的程序設計非常常見:1個Master進程投遞n個Reactor線程;1個Manager進程投遞n個Worker進程。

現在,我們來看看一個簡單的多進程Swoole Server的幾個基本配置:


<?php

$server->set([

   "daemonize"=>true,    

   "reactor_num"=>2,  

   "worker_num"=>4,]

);



$server -> start();


reactor_num:表示Master進程中,Reactor線程總共開多少個,注意,這個可不是越多越好,因為計算機的CPU是有限的,所以一般設置為與CPU核心數量相同,或者兩倍即可。

worker_num:表示啟動多少個Worker進程,同樣,Worker進程數量不是越多越好,仍然設置為與CPU核心數量相同,或者兩倍即可。

讀書萬卷不若自己親手寫一行,試驗一下這個配置下,Server啟動后,pstree的結構。

以上就是“swoole進程模型詳解”的詳細內容,想要了解更多swoole教程歡迎關注編程學習網

掃碼二維碼 獲取免費視頻學習資料

Python編程學習

查 看2022高級編程視頻教程免費獲取