搜索
首页php框架Swoole介绍swoole之进程模型

介绍swoole之进程模型

Apr 15, 2021 pm 05:54 PM
swoole

介绍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。如有侵权,请联系admin@php.cn删除

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器