Swoole 的底层架构通过上图我们可以看到,Swoole 主要包含以下组件:当我们运行启动 Swoole 的 PHP 脚本时,首先会创建该进程,然后由该进程 fork 出 Reactor 线程和 Manager 进程。Reactor:包含在 Master 进程中的多线程程序Reactor 是用来处理 TCP 连接和数据收发(异步非阻塞方式)的程序 。Reactor 主线程在 Accept 新的连接后,会将这个连接分配给一个固定的 Reactor 线程,并由这个线程负责监听此 socket。在 socket 可读时读取数据,并进行协议解析,将请求投递到 Worker 进程;在 socket 可写时将数据发送给 TCP 客户端。Manager:负责 fork 并维护多个 Worker 子进程当有 Worker 子进程中止时,Manager 负责回收并创建新的 Worker 子进程,以便保持 Worker 进程总数不变;当服务器关闭时,Manager 将发送信号给所有 Worker 子进程,通知其关闭服务。以多进程方式运行,每个子进程负责接受由 Reactor 线程投递的请求数据包,并执行 PHP 回调函数处理数据,然后生成响应数据并发给 Reactor 线程,由 Reactor 线程发送给 TCP 客户端。所有请求的处理逻辑都是在 Worker 子进程中完成。功能和 Worker 进程类似,同样以多进程方式运行,但仅用于任务分发,当 Worker 进程将任务异步分发到任务队列时,Task Worker 负责从队列中消费这些任务(同步阻塞方式处理),处理完成后将结果返回给 Worker 进程。Swoole 官方对 Reactor、Worker、Task Worker有一个形象的比喻,如果把基于 Swoole 的 Web 服务器比作一个工厂,那么 Reactor 就是这个工厂的销售员,Worker 是负责生产的工人,销售员负责接订单,然后交给工人生产,而 Task Worker 可以理解为行政人员,负责提工人处理生产以外的杂事,比如订盒饭、收快递,让工人可以安心生产。底层实现原理我们以 MySQL 连接查询为例,对 Swoole 协程底层实现做一个简单的介绍:$server = new Swoole\Http\Server('127.0.0.1', 9501, SWOOLE_BASE);
$server->on('Request', function($request, $response) { $mysql = new Swoole\Coroutine\MySQL(); $res = $mysql->connect([ 'host' => '127.0.0.1', 'user' => 'root', 'password' => 'root', 'database' => 'test', ]); if ($res == false) { $response->end("MySQL connect fail!"); return; } $ret = $mysql->query('show tables', 2); $response->end("swoole response is ok, result=".var_export($ret, true)); });
$server->start(); 在这段代码中,我们启动一个基于 Swoole 实现的 HTTP 服务器监听客户端请求,如果有 onRequest 事件发生,则通过基于 Swoole 协程实现的异步 MySQL 客户端组件对 MySQL 服务器发起连接请求,并执行查询操作,然后将结果以响应方式返回给 HTTP 客户端,下面我们来看一下协程在这段代码中的应用:调用 Swoole\Http\Server 的 onRequest 事件回调函数时,底层会调用 C 函数 coro_create创建一个协程(#1位置),同时保存这个时间点的 CPU 寄存器状态和 ZendVM 堆栈信息; 调用 mysql->connect 时会发生 IO 操作,底层会调用 C 函数 coro_save 保存当前协程的状态,包括 ZendVM 上下文以及协程描述信息,并调用 coro_yield 让出程序控制权,当前的请求会挂起(#2位置); 协程让出程序控制权后,会继续进入 HTTP 服务器的事件循环处理其他事件,这时 Swoole 可以继续去处理其他客户端发来的请求; 当数据库 IO 事件完成后,MySQL 连接成功或失败,底层调用 C 函数 coro_resume 恢复对应的协程,恢复 ZendVM 上下文,继续向下执行 PHP 代码(#3位置); mysql->query 的执行过程与 mysql->connect 一样,也会触发 IO 事件并进行一次协程切换调度; 所有操作完成后,调用 end 方法返回结果,并销毁此协程。 上面这段代码我们借助了 Swoole 实现的协程 MySQL 客户端(Swoole 还提供了很多其他协程客户端,如 Redis、HTTP等,后面我们会详细介绍),所有的编码和之前编写同步代码时并没有任何不同,但是 Swoole 底层会在 IO 事件发生时,保存当前状态,将程序控制权交出,以便 CPU 处理其它事件,当 IO 事件完成时恢复并继续执行后续逻辑,从而实现异步 IO 的功能,这正是协程的强大之处,它可以让服务器同时可以处理更多请求,而不会阻塞在这里等待 IO 事件处理完成,从而极大提高系统的并发性。*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜
上一篇:致用户,微擎8年,我们初心未变 下一篇:原创|java安全-java类加载器 |