从头学习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

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官方文档,结合网上其他资料进行了一些整理和归纳,仅供参考。