Swoole进程模型、第1层:Master主进程
Master主进程
Master进程是Swoole的主进程,主要用于处理Swoole的核心事件驱动。
Master主进程是一个多线程模型,拥有多个独立的Reactor线程。
Master主进程包含Master线程、Reactor线程、心跳检测线程、UDP收包线程。
每个Reactor子线程中都运行着一个epoll函数的实例,Swoole对于事件的监听都会在Reactor线程中实现,比如来自客户端的连接、本地通信使用的管道、异步操作使用的文件以及文件描述符都会注册在epoll函数中。
Master主进程使用select/poll进行IO事件循环,Master主进程中的文件描述符只有几个,Reactor线程使用epoll,因为Reactor线程中会监听大量连接的可读事件,使用epoll可以支持大量的文件描述符。
以HTTP服务器为例,Master主进程负责监听端口,然后接收新的连接,并将这个连接分配给一个Reactor线程,由这个Reactor线程监听此连接,一旦此连接可读时,它会读取数据并解析协议,然后将请求投递到Worker工作进程中去执行。
Master主进程内的回调函数
onStart 服务器启动时主进程的主线程回调此函数
onShutdown 服务器正常结束时发生
Master 线程
Swoole启动后Master主线程会负责监听服务器的socket,如果有新的连接accept,Master主线程会评估每个Reactor线程的连接数量,并将此连接分配给连接最少的Reactor线程。这样做的好处是:
每个Reactor线程持有的连接数非常均衡,没有单个线程负载过高的问题。
解决了集群问题,尤其是拥有多个listen socket时,节约了线程唤醒和切换的开销。
主线程接管了所有信号signal的处理,使Reactor线程运行中可以不被信号打断。
主线程Master在accept新的连接后,会将这个连接分配给一个固定的Reactor线程,并由这个线程负责监听此socket,在socket可读时读取数据,并进行协议解析,最后将请求投递到Worker进程。
Reactor线程
负责维护客户端TCP连接、处理网络IO、处理协议、收发数据。
完全是异步非阻塞的模式
全部都是C代码,除了Start/Shutdown事件回调外,不执行任何PHP代码。
将TCP客户端发送来的数据缓冲、拼接、拆分为完整的请求数据包。
Reactor以多线程的方式运行
Swoole拥有多线程Reactor,所以可以充分利用多核,开启CPU亲和设置后,Reactor线程可以绑定单独的核,节省CPU Cache开销。
Reactor线程负责处理TCP连接,是收发数据的线程。Swoole的Master主线程在accept新的连接后,会将这个连接分配给一个固定的Reactor线程,并由这个线程负责监听此socket。在socket可读时读取数据,并进行协议解析,将请求投递到Worker工作进程。在socket可写时,将数据发送给TCP客户端。
Reactor线程负责维护客户端TCP连接、处理网络IO、处理协议、收发数据,它完全是异步非阻塞的模式。
Reactor线程是全异步非阻塞的,即使Worker进程采用了同步模式,依然不响应Reactor线程的性能。在Worker进程组很繁忙的状态下,Reactor线程完全不受影响,依然可以收发处理数据。
由于TCP是流式的没有边界,所以处理起来很麻烦。Reactor线程可以使用EOF或者包头长度,自动缓存数据、组装数据包,等一个请求完全收到后,再次递交给Worker。
Reactor全部是C代码,除了Start/Shutdown事件回调外,不执行任何PHP代码。它将TCP客户端发来的数据缓冲、拼接、拆分成完整的一个请求数据包。
综上所述,Master主进程中包含两个关键线程:
Master主线程和Reactor线程,
Master主线程用来处理accept()事件,创建新的socket fd,当它接收到新连接后会将新的socket连接放到Reactor线程的事件监听循环中。
Reactor线程负责接收从客户端发送过来的数据,并按协议解析后通过管道pipe传递给Worker工作进程进行处理。
Worker工作进程处理完毕后,会将结果通过管道pipe回传给Reactor线程,Reactor线程再按照协议将结果通过socket发送给客户端。
可以看到Reactor线程负责数据的IO和传输,在Linux系统下这些IO事件都是通过epoll机制来处理的。
心跳包检测线程HeartbeatCheck
Swoole配置了心跳检测后心跳包线程会在固定事件内对所有之前在线的连接发送检测数据包。
UDP收包线程UdpRecv
接收并处理客户端UDP数据包