从头学习swoole
Swoole是一个PHP的C扩展,可用来开发PHP的高性能高并发TCP/UDP Server。Swoole的网络IO部分基于epoll/kqueue事件循环,是全异步非阻塞的。 业务逻辑部分使用多进程同步阻塞方式来运行。这样既保证了Server能够应对高并发和大量TCP连接。又保证业务代码仍然可以简单的编写。
可以说swoole的出现为php续上了一命,swoole可谓是所有phper打家劫舍必备的武器…
一、swoole的进程管理模式
swoole进程分为三种角色:reactor线程、worker进程、taskworker进程
-
reactor线程
负责维护客户端TCP连接、处理网络IO、处理协议、收发数据
完全是异步非阻塞的模式
全部为C代码,除Start/Shudown事件回调外,不执行任何PHP代码
将TCP客户端发来的数据缓冲、拼接、拆分成完整的一个请求数据包
Reactor以多线程的方式运行 -
Worker进程
接受由Reactor线程投递的请求数据包,并执行PHP回调函数处理数据
生成响应数据并发给Reactor线程,由Reactor线程发送给TCP客户端
可以是异步非阻塞模式,也可以是同步阻塞模式
Worker以多进程的方式运行 -
TaskWorker进程
接受由Worker进程通过swoole_server->task/taskwait方法投递的任务
处理任务,并将结果数据返回(使用swoole_server->finish)给Worker进程
完全是同步阻塞模式
TaskWorker以多进程的方式运行 -
图解swoole进程关系:
swoole中的reactor线程、worker进程、taskworker进程之间的关系类似于nginx与php-fpm之间的关系。
master进程启动后,创建reactor线程和manager进程。
reactore用于监听请求,并将请求下发给worker进程。(类似于nginx)
worker进程将耗时的处理转发给task进程处理。(类似于php-fpm)
manager进程用来管理worker进程和task进程,当worker、task进程处理了一定的连接(max_request)后自动重启,防止内存泄漏。
底层会为Worker进程、TaskWorker进程分配一个唯一的ID
不同的Worker和TaskWorker进程之间可以通过sendMessage接口进行通信
二、服务端
不管是tcp、udp、http,还是websocket、redis服务端,都是继承自swoole\server
-
创建server对象
$serv = new Server(string $host, int $port = 0, int $mode = SWOOLE_PROCESS, int $sock_type = SWOOLE_SOCK_TCP);
$host参数用来指定监听的ip地址,如127.0.0.1,或者外网地址,或者0.0.0.0监听全部地址。当采用127.0.0.1或本机的外网地址时,表示只监听来自本机的客户端请求,适用于单体项目。
IPv4使用 127.0.0.1表示监听本机,0.0.0.0表示监听所有地址
IPv6使用::1表示监听本机,:: (相当于0:0:0:0:0:0:0:0) 表示监听所有地址$port监听的端口,如9501
如果$sock_type为UnixSocket Stream/Dgram,此参数将被忽略
监听小于1024端口需要root权限
如果此端口被占用server->start时会失败
$port参数可以设置为0,操作系统会随机分配一个可用的端口,进行监听。可以通过读取$server->port得到分配到的端口号。$mode运行的模式
SWOOLE_PROCESS多进程模式(默认)
SWOOLE_BASE基本模式$sock_type指定Socket的类型,支持TCP、UDP、TCP6、UDP6、UnixSocket Stream/Dgram 6种
-
设置运行时的各项参数
$serv->set(array( 'reactor_num' => 2, //reactor thread num 'worker_num' => 4, //worker process num 'backlog' => 128, //listen backlog 'max_request' => 50, 'dispatch_mode' => 1, ));
各项参数参考官方文档
-
注册server的事件回调
Swoole\Server是事件驱动模式,所有的业务逻辑代码必须写在事件回调函数中。当特定的网络事件发生后,底层会主动回调指定的PHP函数。
- 事件执行顺序
1、所有事件回调均在$server->start后发生
2、服务器关闭程序终止时最后一次事件是onShutdown
3、服务器启动成功后,onStart/onManagerStart/onWorkerStart会在不同的进程内并发执行,但3个事件的执行顺序是不确定的
4、onReceive/onConnect/onClose在Worker进程中触发
5、Worker/Task进程启动/结束时会分别调用一次onWorkerStart/onWorkerStop
6、onTask事件仅在task进程中发生、onFinish事件仅在worker进程中发生-
onStart
在此事件之前Server已进行了如下操作:
1、已创建了manager进程
2、已创建了worker子进程
3、已监听所有TCP/UDP/UnixSocket端口,但未开始Accept连接和请求
4、已监听了定时器接下来要执行:
主Reactor开始接收事件,客户端可以connect到Server
notice:
1、onStart回调中,仅允许echo、打印Log、修改进程名称。不得执行其他操作。onWorkerStart和onStart回调是在不同进程中并行执行的,不存在先后顺序。
2、在onStart回调中可以使用异步和协程的API,但需要注意这可能会与dispatch_func和package_length_func存在冲突。请勿同时使用。
3、onStart回调在return之前服务器程序不会接受任何客户端连接,因此可以安全地使用CURL等PHP提供的同步IO函数。可以在onStart回调中,将$serv->master_pid和$serv->manager_pid的值保存到一个文件中。这样可以编写脚本,向这两个PID发送信号来实现关闭和重启的操作。
BASE模式下没有master进程,因此不存在onStart事件。请不要在BASE模式中使用使用onStart回调函数
- 本主主要参考swoole官方文档,结合网上其他资料进行了一些整理和归纳,仅供参考。