Swoole: PHP的异步、并行、高性能网络通信引擎http://www.swoole.com/
Github:https://github.com/swoolehttps://github.com/matyhtf
安装Swoole须要利用源码安装。暂无Windows版扩展。
源码安装
wget -O swoole.zip https://github.com/swoole/swoole-src/archive/v1.9.11.zipunzip swoole.zipcd swoolephpize./configuremake && make install
pecl安装
由于pecl是须要编译的,以是须要先安装编译器(已安装编译器可以忽略):
yum install -y gcc gcc-c++ make cmake bison autoconf
然后:
pecl install swoolepecl install redis
pecl安装扩展完成后会提示添加so文件到php.ini。示例:
Build process completed successfullyInstalling '/usr/lib64/php/modules/swoole.so'install ok: channel://pecl.php.net/swoole-1.9.11configuration option \公众php_ini\"大众 is not set to php.ini locationYou should add \公众extension=swoole.so\公众 to php.ini
添加示例:
[swoole]extension = /usr/lib64/php/modules/swoole.soSwoole的进程模型
运行模式
Swoole目前统共有三种运行模式,默认为多进程模式(SWOOLE_PROCESS)。
稳定版:v1.9.9预览版:v2.0.7
$serv = new swoole_server(string $host, int $port, int $mode = SWOOLE_PROCESS, int $sock_type = SWOOLE_SOCK_TCP);
实例剖析
我们来利用实例进行剖析:
<?php$server = new \swoole_server(\"大众127.0.0.1\"大众,8088);//默认是多进程模式、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_tcp_server.phppstree -ap|grep swoole_tcp_server | | `-php,2454 swoole_tcp_server.php | | |-php,2456 swoole_tcp_server.php | | | `-php,2458 swoole_tcp_server.php
从系统的输出中,我们可以很容看出server实在有3个进程,进程的pid分别是2454、2456、2458,个中2454是2456的父进程,而2456又是2458的父进程。
以是,实在我们虽然看起来只是启动了一个Server,实在末了产生的是三个进程。
这三个进程中,所有进程的根进程(2454),便是所谓的Master进程;而2456进程,则是Manager进程;末了的2458进程,是Worker进程。
基于此,我们大略梳理一下,当实行的start方法之后,发生了什么:
守护进程模式下,当提高程fork出Master进程,然退却撤退出,Master进程触发OnMasterStart事宜。Master进程启动成功之后,fork出Manager进程,并触发OnManagerStart事宜。Manager进程启动成功时候,fork出Worker进程,并触发OnWorkerStart事宜。非守护进程模式下,则当提高程直接作为Master进程事情。
以是,一个最根本的Swoole Server,至少须要有3个进程,分别是Master进程、Manager进程和Worker进程。
事实上,一个多进程模式下的Swoole Server中,有且只有一个Master进程;有且只有一个Manager进程;却可以有n个Worker进程。
进程模型
Master进程是一个多线程进程,个中有一组非常主要的线程,叫做Reactor线程(组),每当一个客户端连接上做事器的时候,都会由Master进程从已有的Reactor线程中,根据一定规则挑选一个,专门卖力向这个客户端供应坚持链接、处理网络IO与收发数据等做事。分包拆包等功能也是在这里完成。
Manager进程,某种意义上可以看做一个代理层,它本身并不直接处理业务,其紧张事情是将Master进程中收到的数据转交给Worker进程,或者将Worker进程中希望发给客户真个数据转交给Master进程进行发送。
Manager进程还卖力监控Worker进程,如果Worker进程由于某些意外挂了,Manager进程会重新拉起新的Worker进程,有点像Supervisor的事情。而这个特性,也是终极实现热重载的核心机制。
Worker进程实在便是处理各种业务事情的进程,Manager将数据包转交给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方法将数据发回给客户端时,数据则会沿着这个路径逆流而上。Swoole进程/线程构造图:
现在,我们基于上面的例子修正代码,来看看一个大略的多进程Swoole Server的几个基本配置:
PHP5.5或更高版本PHP7.0.13或更高版本
reactor_num:表示Master进程中,Reactor线程统共开多少个,把稳,这个可不是越多越好,由于打算机的CPU是有限的,以是一样平常设置为与CPU核心数量相同,或者两倍即可。
worker_num:表示启动多少个Worker进程,同样,Worker进程数量不是越多越好,仍旧设置为与CPU核心数量相同,或者两倍即可。
我们可以在Shell里运行,利用pstree查看进程模型构造:
php swoole_tcp_server.phppstree -ap|grep swoole_tcp | | `-php,2505 swoole_tcp_server.php | | |-php,2507 swoole_tcp_server.php | | | |-php,2510 swoole_tcp_server.php | | | |-php,2511 swoole_tcp_server.php | | | |-php,2512 swoole_tcp_server.php | | | `-php,2513 swoole_tcp_server.php
回调函数
Swoole作为Server时,回调函数有很多。但可以大略分个类:1) 进程启动时实行的:onStart、onManagerStart、onWorkerStart;onWorkerStop、onManagerStop、onShutdown;onWorkerError2) 客户端交互时触发的:onReceive/onRequest/onPacket/onMessage、onOpen/onConnect、onClose3) Task:onTask、onFinish4) Timer:onTimer
事宜实行顺序:
所有事宜回调均在$server->start后发生做事器关闭程序终止时末了一次事宜是onShutdown做事器启动成功后,onStart/onManagerStart/onWorkerStart会在不同的进程内并发实行。onReceive/onConnect/onClose/onTimer在worker进程(包括task进程)中各自触发worker/task进程启动/结束时会分别调用onWorkerStart/onWorkerStoponTask事宜仅在task进程中发生onFinish事宜仅在worker进程中发生onStart/onManagerStart/onWorkerStart 3个事宜的实行顺序是不愿定的UDP协议下只有onReceive事宜,没有onConnect/onClose事宜如果未设置onPacket回调函数,收到UDP数据包默认会回调onReceive函数onOpen事宜回调是可选的:当WebSocket客户端与做事器建立连接并完成握手后会回调此函数实际利用的时候不是所有回调都可以利用的,例如UDP做事器没有onConnect/onClose;例如吸收数据,在WebSocket里利用onReceive,在HttpServer利用onRequest,在UDPServer利用onPacket。
示例:
<?php$server = new \swoole_server(\公众127.0.0.1\公众,8088);$server->set(array( 'daemonize' => false, 'reactor_num' => 2, 'worker_num' => 4));$server->on('connect', function ($serv, $fd){ echo \"大众client connect. fd is {$fd}\n\"大众;});$server->on('receive', function ($serv, $fd, $from_id, $data){ echo \公众client connect. fd is {$fd}\n\"大众;});$server->on('close', function ($serv, $fd){ echo \"大众client close. fd is {$fd}\n\"大众;});// 以下回调发生在Master进程$server->on(\公众start\"大众, function (\swoole_server $server){ echo \"大众On master start.\n\"大众;});$server->on('shutdown', function (\swoole_server $server){ echo \"大众On master shutdown.\n\"大众;});// 以下回调发生在Manager进程$server->on('ManagerStart', function (\swoole_server $server){ echo \"大众On manager start.\n\"大众;});$server->on('ManagerStop', function (\swoole_server $server){ echo \公众On manager stop.\n\"大众;});// 以下回调也发生在Worker进程$server->on('WorkerStart', function (\swoole_server $server, $worker_id){ echo \"大众Worker start\n\"大众;});$server->on('WorkerStop', function(\swoole_server $server, $worker_id){ echo \"大众Worker stop\n\"大众;});$server->on('WorkerError', function(\swoole_server $server, $worker_id, $worker_pid, $exit_code){ echo \"大众Worker error\n\公众;});$server -> start();
编程须知
不要在代码中实行sleep以及其他就寝函数,这样会导致全体进程壅塞exit/die是危险的,会导致worker进程退出可通过register_shutdown_function来捕获致命缺点,在进程非常退出时做一些要求事情,详细参看/wiki/page/305.htmlPHP代码中如果有非常抛出,必须在回调函数中进行try/catch捕获非常,否则会导致事情进程退出swoole不支持set_exception_handler,必须利用try/catch办法处理非常Worker进程不得共用同一个Redis或MySQL等网络做事客户端,Redis/MySQL创建连接的干系代码可以放到onWorkerStart回调函数中。缘故原由是如果共用1个连接,那么返回的结果无法担保被哪个进程处理。持有连接的进程理论上都可以对这个连接进行读写,这样数据就发生错乱了。详细参考/wiki/page/325.html不能利用类的属性保存客户端连接信息,由于一个worker进程可以处理多个客户端连接,导致类属性数据错乱。常量则是可以的。(本文完) 本文优先在"大众年夜众号\"大众飞鸿影的博客(fhyblog)\公众发布,欢迎关注"大众号及时获取最新文章推送!