三、Swoole 基础学习笔记 - 了解 Swoole 相关进程

作者: 温新

分类: 【Swoole 系列】

阅读: 1394

时间: 2023-01-02 10:14:50

3、Swoole 基础学习笔记 - 了解 Swoole 相关进程

hi,我是温新,一名PHPer

文章基于 Swoole 5.0 版本编写。

学习目标:了解 Swoole 是怎么工作的及相关进程。

说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!

正所谓,"磨刀不误砍柴工",有了上篇文章的快速体验,本篇文章将了解 Swoole 相关进程,以便更好的了解 Swoole 的运行过程。

准备工作

安装 网络管理工具和进程管理工具。

# deepin
apt -y install net-tools psmisc

# Rocky Linux
dnf -y install net-tools psmisc

通过这两个工具来分析 Swoole 启动后的进程。

Swoole 是如何运行的

本篇文章会延续 Swoole 基础学习笔记 - 先把 Swoole 跑起来 案例来了解相关进程及线程。在这之前要先来了解一下 Swoole 是如何运行的。

Swoole 运行流程图

基于这个运行流程图,我们来看看 $server->start(); 发生了什么。服务启动后如有如下操作:

Swoole 服务启动后发生的事:启动成功后会创建 worker_num + 2 个进程。 Master 进程 + Manager 进程 + serv->worker_num 个进程。比如说当我们设置进程数为 2 时,实际上启动了 4 个进程;结合运行流程图来看,服务启动后会创建 Master 进程、Worker 进程。

现在我们来总结下 Swoole 进程模型:Master - Manager - Worker 进程。这也是为什么设置 worker_num 进程启动后,查看进程会多出两个进程的原因,而这两个进程就是 master 进程和 manager 进程。

Swoole 进程/线程结构图

接下来再看看这些进程和线程都有什么作用,如下:

Master 进程:为主进程,主进程中有多个 Reactor 线程,基于 epoll/kqueue 进行网络事件轮询。收到数据后转发到 Worker 进程去处理;

Manager 进程:为管理进程,是对所有 Worker 进程生命周期结束或发生异常时自动回收,并创建新的 Worker 进程;

Worker 进程:为工作进程,对收到的数据进行处理,包括协议解析和响应请求(未设置 worker_num,底层会启动与 CPU 数量一致的 Worker 进程);

Task 进程:异步工作进程,接收由Worker进程投递的任务,TaskWorker以多进程的方式运行,是同步阻塞模式;

Reactor 线程:reactor 线程由 master 进程创建,reactor 负责维护客户端 TCP 连接、处理网络 IO、处理协议、收发数据。

了解了 Swoole 进程与线程,那么他们之间有什么关系呢?用个通俗的例子来说明,Server 是饭馆,Reactor 是服务员,Worker 是厨师。服务员将菜单拿给客户,点完菜后,服务员将菜单拿给大厨,在这个过程中,Worker 去生产客户所需要的菜,TaskWorker 可以理解为大厨的徒弟,可以帮助大厨干些琐事。

Swoole 启动后的进程与线程

结合上述知识,我们现在来看看 Swoole Server 启动后的进程与线程,

查看 Master 进程

$netstat -nltp
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
# 9501,我们启动的 server 服务,这是 master 主进程
tcp        0      0 0.0.0.0:9501            0.0.0.0:*               LISTEN      76459/php    

查看进程树

$pstree -p 76459
# 76459 master 进程;
# 76460 manager 进程
# 76467... worker 进程
# 76461... 线程
php(76459)─┬─php(76460)─┬─php(76467)
           │            ├─php(76470)
           │            ├─php(76471)
           │            ├─php(76472)
           │            ├─php(76473)
           │            ├─php(76474)
           │            ├─php(76475)
           │            ├─php(76476)
           │            ├─php(76477)
           │            ├─php(76478)
           │            ├─php(76479)
           │            ├─php(76480)
           │            ├─php(76481)
           │            ├─php(76482)
           │            ├─php(76483)
           │            └─php(76484)
           ├─{php}(76461)
           ├─{php}(76462)
           ├─{php}(76463)
           ├─{php}(76464)
           ├─{php}(76465)
           ├─{php}(76466)
           ├─{php}(76468)
           └─{php}(76469)

通过进程树可以清晰看出进程间的关系,76459 master 进程下有线程,76460 manager 进程下有 worker进程。查看了进程与线程,有了这样一丝疑惑,怎么有这么多进程与线程?

当没有设置进程时,Swoole 线程与电脑 CPU 核数有关,我的电脑 CPU 为 8 核,因此有 8 个线程。这个值是可以配置的,下面我们就来看看。

set 方法设置进程数与线程数

set() 用于设置运行时的各项参数。服务器启动后通过 $serv->setting 来访问 Server->set 方法设置的参数数组。

<?php

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);

$server->set([
    // 设置 3 个 worker 进程
    'worker_num'    =>  3,
    // 设置 2 个 reactor 线程
    'reactor_num'   =>  2,
]);

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

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
    $server->send($fd, '服务器返回:' . $data) . PHP_EOL;
});

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

$server->start();

修改文件后需要中断服务,然后再重新启动才能生效。当前设置 worker_num 为 3 个进程后,猜一猜会启动多少个进程?答案是会启动 5 个进程,如果不明白为什么会启动 5 个进程,可以看看上面的内容。

$pstree -p 91875
php(91875)─┬─php(91876)─┬─php(91879)
           │            ├─php(91880)
           │            └─php(91881)
           ├─{php}(91877)
           └─{php}(91878)

设置进程名称

为了更好的区分是什么是进程,现在来引入一些还没有学习到的知识——事件回调,以及用来设置进程名称的函数 swoole_set_process_name,下来就直接来看案例吧:

<?php

$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);

$server->set([
    'worker_num' 	 => 3,
    // task 任务进程
    'task_worker_num'=> 2,
]);

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

$server->on('Receive', function ($server, $fd, $reactorId, $data) {
});

// 设置 task 进程后,必须调用任务回调,不然会报错
$server->on('Task', function (Swoole\Server $server, Swoole\Server\Task $task) {
});


$server->on('Start', function ($server) {
    swoole_set_process_name('swoole:master');
});

$server->on('ManagerStart', function ($server) {
    swoole_set_process_name('swoole:manager');
});

$server->on('WorkerStart', function ($server, $workerId) {
    if($workerId >= $server->setting['worker_num']) {
        swoole_set_process_name("swoole:task worker");
    } else {
        swoole_set_process_name("swoole:php worker");
    }
});

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

$server->start();

现在为进程设置了名称,我们就来看看设置进程名称的进程情况:

$ps aux | grep swoole
codeing    97668  0.4  0.1 335168 27444 pts/1    Sl+  23:50   0:00 swoole:master
codeing    97669  0.0  0.0 115996 10416 pts/1    S+   23:50   0:00 swoole:manager
codeing    97673  0.0  0.0 118048  8704 pts/1    S+   23:50   0:00 swoole:task worker
codeing    97674  0.0  0.0 118048  8712 pts/1    S+   23:50   0:00 swoole:task worker
codeing    97675  0.0  0.0 118192 11460 pts/1    S+   23:50   0:00 swoole:php worker
codeing    97676  0.0  0.0 118192 11460 pts/1    S+   23:50   0:00 swoole:php worker
codeing    97677  0.0  0.0 118192 11460 pts/1    S+   23:50   0:00 swoole:php worker
codeing    97682  0.0  0.0  13864   836 pts/2    S+   23:51   0:00 grep swoole

现在可以很清晰的看哪个是 master,哪个是manager等进程了。 好了,本篇文章到此结束,我是温新。

请登录后再评论