swoole入门4-初识swoole

运行流程图



图片描述

当启动一个Swoole应用时,一共会建立2+n+m个进程,2为一个Master进程和一个Manager进程,其中n为Worker进程数,m为TaskWorker进程数。

名词解释

Master进程

主进程,该进程会建立Manager进程、Reactor线程,UDP收包线程,心跳检测线程等线程

Manger进程

管理进程,该进程的做用是建立、管理全部的Worker进程和TaskWorker进程。
  • 子进程结束运行时,manager进程负责回收此子进程,避免成为僵尸进程。并建立新的子进程
  • 服务器关闭时,manager进程将发送信号给全部子进程,通知子进程关闭服务
  • 服务器reload时,manager进程会逐个关闭/重启子进程

Worker进程

工做进程,全部的业务逻辑代码均在此进程上运行。当Reactor线程接收到来自客户端的数据后,会将数据打包经过管道发送给某个Worker进程。
  • 接受由Reactor线程投递的请求数据包,并执行PHP回调函数处理数据
  • 生成响应数据并发给Reactor线程,由Reactor线程发送给TCP客户端
  • 能够是异步非阻塞模式,也能够是同步阻塞模式
  • Worker以多进程的方式运行

TaskWorker进程

一种特殊的工做进程,该进程的做用是处理一些耗时较长的任务,以达到释放Worker进程的目的。
  • 接受由Worker进程经过swoole_server->task/taskwait方法投递的任务
  • 处理任务,并将结果数据返回(使用swoole_server->finish)给Worker进程
  • 彻底是同步阻塞模式
  • TaskWorker以多进程的方式运行

Reactor线程

实际运行Linux中是epoll实例,MacOS中为Kqueue实例,用于accept客户端链接以及接收客户端数据。

Swoole的主进程是一个多线程的程序。其中有一组很重要的线程,称之为Reactor线程。它就是真正处理TCP链接,收发数据的线程。

Swoole的主线程在Accept新的链接后,会将这个链接分配给一个固定的Reactor线程,并由这个线程负责监听此socket。

在socket可读时读取数据,并进行协议解析,将请求投递到Worker进程。在socket可写时将数据发送给TCP客户端。
  • 负责维护客户端TCP链接、处理网络IO、处理协议、收发数据
  • 彻底是异步非阻塞的模式
  • 所有为C代码,除Start/Shudown事件回调外,不执行任何PHP代码
  • 将TCP客户端发来的数据缓冲、拼接、拆分红完整的一个请求数据包
  • Reactor以多线程的方式运行

运行机制

Swoole是php的扩展,一旦运行后就会接管PHP的控制权,进入事件循环。 

当某种IO(网络IO)事件发生时,Swoole 会回调用户设置的指定回调函数。
    
Swoole承担了底层网络事件的监听及各类底层事件处理,当收到请求时,会触发事件提醒,而后将控制权转交预先注册的事件回调函数,来进行后续的处理。

能够理解为Reactor就是nginx,Worker就是php-fpm。Reactor线程异步并行地处理网络请求,而后再转发给Worker进程中去处理。Reactor和Worker间经过UnixSocket进行通讯。

Swoole提供的TaskWorker是一套更完整的方案,将任务的投递、队列、php任务处理进程管理合为一体。经过底层提供的API能够很是简单地实现异步任务的处理。

另外TaskWorker还能够在任务执行完成后,再返回一个结果反馈到Worker。

Swoole的Reactor、Worker、TaskWorker之间能够紧密的结合起来,提供更高级的使用方式。

一个更通俗的比喻,假设Server就是一个工厂,Master是董事长,Manager是CEO,那Reactor就是销售经理,接受客户订单。而Worker就是工人,当销售接到订单后,Worker去工做生产出客户要的东西。

而TaskWorker能够理解为行政人员,能够帮助Worker干些琐事,让Worker专心工做。
所谓的回调函数(CallBack) 就比如是张开了夹子的捕鼠器,咱们设定当有老鼠踩到捕鼠器的时候,他会关闭夹子而后捉住老鼠,咱们放置捕鼠器的时候,捕鼠器并无真的抓老鼠。这个设定就是回调,他不马上执行,会在遇到触发条件(事件)时执行,在上面的示例当中咱们放置了3个捕鼠器(回调函数),咱们只须要知道他会在特定老鼠(事件)踩到的时候(发生的时候)去执行咱们指望的功能就好。
  • 底层会为Worker进程、TaskWorker进程分配一个惟一的ID
  • 不一样的Worker和TaskWorker进程之间能够经过sendMessage接口进行通讯

运行周期

程序全局期

在swoole_server->start以前就建立好的对象,咱们称之为程序全局生命周期。
 
 这些变量在程序启动后就会一直存在,直到整个程序结束运行才会销毁。
 
 有一些服务器程序可能会连续运行数月甚至数年才会关闭/重启,那么程序全局期的对象在这段时间持续驻留在内存中的。
 
 程序全局对象所占用的内存是Worker进程间共享的,不会额外占用内存。
 
 这部份内存会在写时分离(COW),在Worker进程内对这些对象进行写操做时,会自动从共享内存中分离,变为进程全局对象。
 
 程序全局期include/require的代码,必须在整个程序shutdown时才会释放,reload无效。

进程全局期

swoole拥有进程生命周期控制的机制,一个Worker子进程处理的请求数超过max_request配置后,就会自动销毁。
 
 Worker进程启动后建立的对象(onWorkerStart中建立的对象),在这个子进程存活周期以内,是常驻内存的。
 
 onConnect/onReceive/onClose 中均可以去访问它。
 
 进程全局对象所占用的内存是在当前子进程内存堆的,并不是共享内存。对此对象的修改仅在当前Worker进程中有效。
 
 进程期include/require的文件,在reload后就会从新加载。

会话期

会话期是在onConnect后建立,或者在第一次onReceive时建立,onClose时销毁。一个客户端链接进入后,建立的对象会常驻内存,直到此客户端离开才会销毁。
 
 swoole中会话期的对象直接是常驻内存,不须要session_start之类操做。
 
 能够直接访问对象,并执行对象的方法。

请求期

请求期就是指一个完整的请求发来,也就是onReceive收到请求开始处理,直到返回结果发送response。
 
 这个周期所建立的对象,会在请求完成后销毁。
 
 swoole中请求期对象与普通PHP程序中的对象就是同样的。
 
 请求到来时建立,请求结束后销毁。

4种PHP回调函数风格

匿名函数

$server->on('Request', function ($req, $resp) use ($a, $b, $c) {
       echo "hello world";
});
可以使用use向匿名函数传递参数

类静态方法

class A
{
    static function test($req, $resp)
    {
        echo "hello world";
    }
}
$server->on('Request', 'A::Test');
$server->on('Request', array('A', 'Test'));

对象方法

class A
{
    function test($req, $resp)
    {
        echo "hello world";
    }
}

$object = new A();
$server->on('Request', array($object, 'test'));

函数

function my_onRequest($req, $resp)
{
    echo "hello world";
}
$server->on('Request', 'my_onRequest');

编程须知

注意事项

  • 不要在代码中执行sleep以及其余睡眠函数,这样会致使整个进程阻塞
  • 在swoole程序中禁止使用exit/die,若是PHP代码中有exit/die,当前工做的Worker进程、Task进程、User进程、以及swoole_process进程会当即退出。使用exit/die后Worker进程会由于异常退出, 被master进程再次拉起, 最终形成进程不断退出又不断启动和产生大量警报日志。
  • mt_rand随机数,在Swoole中若是在父进程内调用了mt_rand,不一样的子进程内再调用mt_rand返回的结果会是相同的。因此必须在每一个子进程内调用mt_srand从新播种。
  • while循环的影响,异步程序若是遇到死循环,事件将没法触发。异步IO程序使用Reactor模型,运行过程当中必须在reactor->wait处轮询。若是遇到死循环,那么程序的控制权就在while中了,reactor没法获得控制权,没法检测事件,因此IO事件回调函数也将没法触发。
  • 可经过register_shutdown_function来捕获致命错误,在进程异常退出时作一些清理工做
  • PHP代码中若是有异常抛出,必须在回调函数中进行try/catch捕获异常,不然会致使工做进程退出
  • 不支持set_exception_handler,必须使用try/catch方式处理异常
  • Worker进程不得共用同一个Redis或MySQL等网络服务客户端,Redis/MySQL建立链接的相关代码能够放到onWorkerStart回调函数中。

异步编程

  • 异步程序要求代码中不得包含任何同步阻塞操做
  • 异步与同步代码不能混用,一旦应用程序使用了任何同步阻塞的代码,程序即退化为同步模式

类/函数重复定义

新手很是容易犯这个错误,因为Swoole是常驻内存的,因此加载类/函数定义的文件后不会释放。所以引入类/函数的php文件时必需要使用include_once或require_once,否会发生cannot redeclare function/class 的致命错误。

进程隔离

进程隔离也是不少新手常常遇到的问题。修改了全局变量的值,为何不生效,缘由就是全局变量在不一样的进程,内存空间是隔离的,因此无效。因此使用Swoole开发Server程序须要了解进程隔离问题。
  • 不一样的进程中PHP变量不是共享,即便是全局变量,在A进程内修改了它的值,在B进程内是无效的
  • 若是须要在不一样的Worker进程内共享数据,能够用Redis、MySQL、文件、SwooleTable、APCu、shmget等工具实现
  • 不一样进程的文件句柄是隔离的,因此在A进程建立的Socket链接或打开的文件,在B进程内是无效,即便是将它的fd发送到B进程也是不可用的
相关文章
相关标签/搜索