编程学习网 > 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高级编程视频教程免费获取