一、进程的基本知识
什么是进程,所谓进程其实就是操作系统中一个正在运行的程序,我们在一个终端当中,通过 php,运行一个 php 文件,这个时候就相当于我们创建了一个进程,这个进程会在系统中驻存,申请属于它自己的内存空间系统资源并且运行相应的程序
对于一个进程来说,它的核心内容分为两个部分,一个是它的内存,这个内存是这进程创建之初从系统分配的,它所有创建的变量都会存储在这一片内存环境当中
一个是它的上下文环境我们知道进程是运行在操作系统的,那么对于程序来说,它的运行依赖操作系统分配给它的资源,操作系统的一些状态。
在操作系统中可以运行多个进程的,对于一个进程来说,它可以创建自己的子进程,那么当我们在一个进程中创建出若干个子进程的时候那么可以看到如图,子进程和父进程一样,拥有自己的内存空间和上下文环境
二、Swoole 进程结构
Swoole 的高效不仅仅于底层使用 c 编写,他的进程结构模型也使其可以高效的处理业务,我们想要深入学习,并且在实际的场景当中使用必须了解,下面我们先看一下结构图:
首先先介绍下 swoole 的这几种进程分别是干什么的:
从这些层级的名字,我们先大概说一下,下面这些层级分别是干什么的,做一个详细的说明。
Master 进程:主进程
Manger 进程:管理进程
Worker 进程:工作进程
Task 进程:异步任务工作进程
1、Master 进程
第一层,Master 进程,这个是 swoole 的主进程, 这个进程是用于处理 swoole 的核心事件驱动的,那么在这个进程当中可以看到它拥有一个 MainReactor[线程]以及若干个 Reactor[线程],swoole 所有对于事件的监听都会在这些线程中实现,比如来自客户端的连接,信号处理等。
每一个线程都有自己的用途,下面多每个线程有一个了解
MainReactor(主线程)
主线程会负责监听 server socket,如果有新的连接 accept,主线程会评估每个 Reactor 线程的连接数量。将此连接分配给连接数最少的 reactor 线程,做一个负载均衡。
Reactor 线程组
Reactor 线程负责维护客户端机器的 TCP 连接、处理网络 IO、收发数据完全是异步非阻塞的模式。swoole 的主线程在 Accept 新的连接后,会将这个连接分配给一个固定的 Reactor 线程,在 socket 可读时读取数据,并进行协议解析,将请求投递到 Worker 进程。在 socket 可写时将数据发送给 TCP 客户端。
心跳包检测线程(HeartbeatCheck)
Swoole 配置了心跳检测之后,心跳包线程会在固定时间内对所有之前在线的连接发送检测数据包
UDP 收包线程(UdpRecv)
接收并且处理客户端 udp 数据包
2、管理进程 Manager
Swoole 想要实现最好的性能必须创建出多个工作进程帮助处理任务,但 Worker 进程就必须 fork 操作,但是 fork 操作是不安全的,如果没有管理会出现很多的僵尸进程,进而影响服务器性能,同时 worker 进程被误杀或者由于程序的原因会异常退出,为了保证服务的稳定性,需要重新创建 worker 进程。
Swoole 在运行中会创建一个单独的管理进程,所有的 worker 进程和 task 进程都是从管理进程 Fork 出来的。管理进程会监视所有子进程的退出事件,当 worker 进程发生致命错误或者运行生命周期结束时,管理进程会回收此进程,并创建新的进程。换句话也就是说,对于 worker、task 进程的创建、回收等操作全权有“保姆”Manager 进程进行管理。
再来一张图梳理下 Manager 进程和 Worker/Task 进程的关系。
3、Worker 进程
worker 进程属于 swoole 的主逻辑进程,用户处理客户端的一系列请求,接受由 Reactor 线程投递的请求数据包,并执行 PHP 回调函数处理数据生成响应数据并发给 Reactor 线程,由 Reactor 线程发送给 TCP 客户端可以是异步非阻塞模式,也可以是同步阻塞模式
4、Task 进程
taskWorker 进程这一进城是 swoole 提供的异步工作进程,这些进程主要用于处理一些耗时较长的同步任务,在 worker 进程当中投递过来。
三、进程查看及流程梳理
当启动一个 Swoole 应用时,一共会创建 2 + n + m 个进程,2 为一个 Master 进程和一个 Manager 进程,其中 n 为 Worker 进程数。m 为 TaskWorker 进程数。
默认如果不设置,swoole 底层会根据当前机器有多少 CPU 核数,启动对应数量的 Reactor 线程和 Worker 进程。我机器为 1 核的。Worker 为 1。
所以现在默认我启动了 1 个 Master 进程,1 个 Manager 进程,和 1 个 worker 进程,TaskWorker 没有设置也就是为 0,当前 server 会产生 3 个进程。
在启动了 server 之后,在命令行查看当前产生的进程
这三个进程中,所有进程的根进程,也就是例子中的 2123 进程,就是所谓的 Master 进程;而 2212 进程,则是 Manager 进程;最后的 2321 进程,是 Worker 进程。
client 跟 server 的交互
1、client 请求到达 Main Reactor,Client 实际上是与 Master 进程中的某个 Reactor 线程发生了连接。
2、Main Reactor 根据 Reactor 的情况,将请求注册给对应的 Reactor (每个 Reactor 都有 epoll。用来监听客户端的变化)
3、客户端有变化时 Reactor 将数据交给 worker 来处理
4、worker 处理完毕,通过进程间通信 (比如管道、共享内存、消息队列) 发给对应的 reactor。
5、reactor 将响应结果发给相应的连接请求处理完成
示意图:
后续准备
本文是在自己学习 Swoole 接触到的一些知识,在初步整理后发送出来,希望能与大家一起学习,文章不足等问题大家可以一起讨论学习,欢迎骚扰~~。后面准备从网络模型入手更好的理解 swoole 的实现原理,比较与传统 PHP-FPM 工作模式的问题,之前出过一篇关于(一)如何实现一个单进程阻塞的网络服务器大家可以先了解下,如何一步步演变为多进程 master-worker 模型。
欢迎大家指正文章问题~