首頁  >  文章  >  php框架  >  介紹swoole之進程模型

介紹swoole之進程模型

coldplay.xixi
coldplay.xixi轉載
2021-04-15 17:54:302870瀏覽

介紹swoole之進程模型

初識server一文的時候我們說過,swoole是事件驅動的。在使用swoole的過程中,我們也體會到,swoole的使用非常簡單,僅僅註冊相應的回調處理我們的業務邏輯即可。

但是,在繼續學習swoole之前,我們有必要再看一看swoole的運行流程和進程模型。

推薦(免費):swoole

#前面兩篇文章我們已經對server和task做了簡單的介紹,後面再對server的創作以及腳本的執行,如無特殊說明均在CLI下執行,我就不囉嗦了。

現在,我們建立一個簡單的server來分析一下,檔案命名為server-process.php

$serv = new swoole_server('127.0.0.1', 9501);
$serv->set([
    'worker_num' => 2,
    'task_worker_num' => 1,
]);
$serv->on('Connect', function ($serv, $fd) {
});
$serv->on('Receive', function ($serv, $fd, $fromId, $data) {
});
$serv->on('Close', function ($serv, $fd) {
});
$serv->on('Task', function ($serv, $taskId, $fromId, $data) {
});
$serv->on('Finish', function ($serv, $taskId, $data) {
});

$serv->start();

注意這裡我們選擇了兩個worker進程個一個task進程,那是不是就代表創建這個server就是開啟了3個進程呢?我們來看下

新開一個終端,我們用ps指令看下結果

$ ps aux | grep server-process
root     21843  xxx... php server-process.php
root     21844  xxx... php server-process.php
root     21846  xxx... php server-process.php
root     21847  xxx... php server-process.php
root     21848  xxx... php server-process.php
root     21854  xxx... grep --color=auto server-process

為了方便閱讀,ps的結果中部分不重要資料已經被稍加處理了。

排除最後一個結果(最後一個是我們運行的ps命令)我們發現,竟然有多達5個相似的進程在運行,按照我們理解,不應該是3個嗎,怎麼多了兩個呢?

還記得我們在進程/執行緒一文中說過的多進程的實作嗎?我們說到多進程的實作一般會被設計Master-Worker模式,常見的nginx預設的多進程模式也正是如此,當然swoole預設的也是多進程模型。

比較Master-Worker模式,swoole的行程模型可以用Master-Manager-Worker來形容。即在Master-Worker的基礎上又增加了一層Manager進程。這也就解答了我們開頭拋出的問題為什麼是5個行程而不是3個行程了。 (1個Master進程 1個Manager進程 2個Worker進程 1個Task進程)

正所謂“存在即合理”,我們來看看Master\Manager\Worker三種進程各自存在的原因。

Master程序是一個多執行緒程式。註解:按照我們先前的理解,多個執行緒是運行在單一進程的上下文中的,其實對於單一進程中的每一個線程,都有它自己的上下文,但是由於共同存在於同一進程,所以它們也共享這個進程,包括它的程式碼、資料等等。

再回來繼續說Master進程,Master進程就是我們的主進程,掌管生殺大權,它掛了,那底下的都得玩完。 Master進程,包含主線程,多個Reactor線程等。

每一個執行緒都有自己的用途,例如主執行緒用於Accept、訊號處理等操作,而Reactor執行緒是處理tcp連接,處理網路IO,收發資料的執行緒。

說明兩點:

  • 主執行緒的Accept操作,socket服務端常用accept阻塞,上一節介紹socket程式的時候有一個配圖,可以看看
  • 訊號處理,訊號就相當於一則訊息,例如我們常操作的Ctrl C其實就是給Master進程的主執行緒發送一個SIGINT的訊號,意思是你可以終止啦,訊號有很多種,後面還有介紹

通常,主線程處理完新的連接後,會將這個連接分配給固定的Reactor線程,並且這個Reactor線程會一直負責監聽此socket(上文中後面對socket更新為socket即套接字,是用來與另一個進程進行跨網路通訊的文件,文件可讀可寫),換句話說當此socket可讀時,會讀取數據,並將該請求分配給worker進程,這也解釋了我們在swoole初識講解worker進程內的回調onReceive的第三個參數$fromId的含義;當此socket可寫時,會把數據發送給tcp客戶端。

用一張圖清晰的梳理下

那swoole為啥不能像Nginx一樣,是Master-Worker進程結構的呢? Manager進程是乾啥的?

這個我正準備說。

我們知道,在Master-Worker模型中,Master只有一個,Worker是由父程序Master進程複製出來的,且Worker進程可以有多個。

註解:在linux中,父進程可以透過呼叫fork函數來建立一個新的子進程,子進程是父進程的一個副本,幾乎但不完全相同,二者的最大差異就是都擁有自己獨立的進程ID,即PID。

對於多執行緒的Master進程而言,想要多Worker進程就必須fork操作,但是fork操作是不安全的,所以,在swoole中,有一個專職的Manager進程,Manager進程就專門負責worker/task流程的fork操作與管理。換句話說,對於worker進程的建立、回收等操作全權有「保姆」Manager進程進行管理。

通常,worker进程被误杀或者由于程序的原因会异常退出,Manager进程为了保证服务的稳定性,会重新拉起新的worker进程,意思就是Worker进程你发生意外“死”了,没关系,我自身不“死”,就可以fork千千万万个你。

当然,Master进程和Manager进程我们是不怎么关心的,从前面两篇文章我们了解到,真正实现业务逻辑,是在worker/task进程内完成的。

再来一张图梳理下Manager进程和Worker/Task进程的关系。

再回到我们开篇抛出的的5个进程的问题,ps的结果简直一模一样,有没有办法能区分这5个进程哪个是哪个呢?

有同学要说啦,既然各个进程之间存在父子关系,那我们就可以通过linux的pstree命令查看结果。

$ pstree | grep server-process

 | |   \-+= 02548 manks php server-process.php

 | |     \-+- 02549 manks php server-process.php

 | |       |--- 02550 manks php server-process.php

 | |       |--- 02551 manks php server-process.php

 | |       \--- 02552 manks php server-process.php

 |     \--- 02572 manks grep server-process

注:centos下命令可修改为 pstree -ap | grep server-process

从结果中我们可以看出,进程id等于02548的进程就是Master进程,因为从结构上看就它是“父”嘛,02549是Manager进程,Worker进程和Task进程就是02550、02551和02552了(每个人的电脑上显示的进程id可能不同,但顺序是一致的,依照此模型分析即可)。

我们看到pstree命令也只能得到大致结果,而且在事先不知道的情况下,根本无法区分Worker进程和Task进程。

在swoole中,我们可以在各个进程启动和关闭的回调中去解决上面这个问题。各个进程的启动和关闭?那岂不是又要记住主进程、Manager进程、Worker进程,二三得六,6个回调函数?

是的,不过这6个是最简单也是最好记的,你实际需要了解的可能还要更多。

Master进程:
    启动:onStart
    关闭:onShutdown
Manager进程:
    启动:onManagerStart
    关闭:onManagerStop
Worker进程:
    启动:onWorkerStart
    关闭:onWorkerStop

提醒:task_worker也会触发onWorkerStart回调。

是不是很好记?那我们就在server-process.php中通过上面这几种回调来实现对各个进程名的修改。

$serv->on("start", function ($serv){
    swoole_set_process_name('server-process: master');
});
// 以下回调发生在Manager进程
$serv->on('ManagerStart', function ($serv){
    swoole_set_process_name('server-process: manager');
});
$serv->on('WorkerStart', function ($serv, $workerId){
    if($workerId >= $serv->setting['worker_num']) {
        swoole_set_process_name("server-process: task");
    } else {
        swoole_set_process_name("server-process: worker");
    }
});

注意:因mac下不支持swoole_set_process_name函数,即不能修改进程名,我们换台centos运行下看看结果(实际上你的服务器也不可能是mac)

# ps aux | grep server-process
root     27546  xxx... server-process: master
root     27547  xxx... server-process: manager
root     27549  xxx... server-process: task worker
root     27550  xxx... server-process: worker
root     27551  xxx... server-process: worker
root     27570  xxx... grep --color=auto simple

运行结果谁是谁一目了然,简直了!

有同学傻眼了,说在workerStart回调中写的看不明白,worker进程和task进程怎么区分的?

我来解释一下:在onWorkerStart回调中,$workerId表示的是一个值,这个值的范围是0~worker_num,worker_num是我们的对worker进程的配置,其中0~worker_num表示worker进程的标识,包括0但不包括worker_num;worker_num~worker_num+task_worker_num是task进程的标识,包括worker_num不包括worker_num+task_worker_num。

按照高中学的区间的知识可能更好理解,以我们案例的配置,workerId的值的范围就是[0,2],[0,2)表示worker进程,[2,3)就表示task_worker进程。

swoole的进程模型很重要,本篇掌握不好,后面的理解可能就会有些问题。

补充:

我们在onWorkerStart的回调中,用了serv−>setting去获取配置的server信息,在swoole中预留了一些swooleserver的属性,我们可以在回调函数中访问。比如说我们可以用serv−>setting去获取配置的server信息,在swoole中预留了一些swooleserver的属性,我们可以在回调函数中访问。比如说我们可以用serv->connections属性获取当前server的所有的连接,再比如我们可以通过$serv->master_pid属性获取当前server的主进程id等等。

以上是介紹swoole之進程模型的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除