参考文献
进程结构官方文档:https://wiki.swoole.com/#/learn?id=diff-process
进程结构图:https://wiki.swoole.com/#/server/init?id=进程线程结构图
图例:https://www.kdocs.cn/view/l/sfUsBSd2K1f2
图例:https://www.kdocs.cn/view/l/snjd2FtKwsew
Swoole进程结构
- Master 进程 (主进程)
- Manager 进程 (管理进程)
- Worker 进程 (工作进程)
- task 进程 (异步任务工作进程)
client与server的交互
1、client
请求到达main reactor
,与master
进程中的某个reactor
线程连接
2、main reactor
将请求注册给对应的reactor
3、客户端有变化时reactor
将数据交给worker
处理
4、worker
处理完毕,通过进程间通信,发给对应的reactor
5、reactor
将响应结果发给相应的连接请求处理完成
6、Manager
负责 (创建/回收)worker/task
进程
主要进程说明
Master进程
Master进程主要用来保证Swoole框架机制的运行。它会创建几个功能性的线程:
- Reactor线程:就是真正处理TCP连接,收发数据的线程。swoole的主线程在Accept新的连接后,会将这个连接分配给一个固定的Reactor线程,并由这个线程负责监听此socket。在socket可读时读取数据,并进行协议解析,将请求投递到Worker进程。在socket可写时将数据发送给TCP客户端。
- Master线程(主线程): 负责:Accept新的连接、UNIX PROXI信号处理、定时器任务。
- 心跳包检测线程:(略)
- UDP收包线程:(略)
Manager进程
swoole中Worker/Task进程都是由Manager进程Fork并管理的。
- 子进程结束运行时,manager进程负责回收此子进程,避免成为僵尸进程。并创建新的子进程
- 服务器关闭时,manager进程将发送信号给所有子进程,通知子进程关闭服务
- 服务器reload时,manager进程会逐个关闭/重启子进程
为什么不是Master进程呢,主要原因是Master进程是多线程的,不能安全的执行fork操作。
Worker进程
- 接受由Reactor线程投递的请求数据包,并执行PHP回调函数处理数据
- 生成响应数据并发给Reactor线程,由Reactor线程发送给TCP客户端
- 可以是异步非阻塞模式,也可以是同步阻塞模式
- Worker以多进程的方式运行
Swoole提供了完善的进程管理机制,当Worker进程异常退出,如发生PHP的致命错误、被其他程序误杀,或达到max_request次数之后正常退出。主进程会重新拉起新的Worker进程。 Worker进程内可以像普通的apache+php或者php-fpm中写代码。不需要像Node.js那样写异步回调的代码。
Task进程
- 接受由Worker进程通过
swoole_server->task/taskwait
方法投递的任务 - 处理任务,并将结果数据返回给Worker进程
- 完全是同步阻塞模式
- Task以多进程的方式运行
Task进程的全称是task_worker
进程,是一种特殊的worker
进程。所以onWorkerStart
在task进程中也会被调用。
当$worker_id >= $serv->setting['worker_num']
时表示这个进程是task_worker
,否则,代表此进程是worker进程。
进程与事件回调的对应关系
Master进程内的回调函数
onStart
onShutdown
onMasterConnect
onMasterClose
onTimer
Worker进程内的回调函数
onWorkerStart
onWorkerStop
onConnect
onClose
onReceive
onTimer
onFinish
Task进程内的回调函数
onTask
onWorkerStart
Manager进程内的回调函数
onManagerStart
onManagerStop
通俗比喻
假设Server
就是一个工厂,那Reactor
就是销售,接受客户订单。而Worker
就是工人,当销售接到订单后,Worker
去工作生产出客户要的东西。而TaskWorker
可以理解为行政人员,可以帮助Worker
干些杂事,让Worker
专心工作。 Manager
相当于HR,负责招聘员工(Worker
),或者把不干活的员工(Worker
)开除。
Swoole进程测试
测试代码
<?php
$server = new Swoole\Server('127.0.0.1', 9503);
$server->on('connect', function ($server, $fd){
echo "connection open: {$fd}\n";
});
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
$server->send($fd, "Swoole: {$data}");
$server->close($fd);
});
$server->on('close', function ($server, $fd) {
echo "connection close: {$fd}\n";
});
$server->start();