Swoole生命周期

PHP底层工作原理

Swoole生命周期_第1张图片
PHP体系架构

PHP的相关进程是随着Web服务器如Apache、Nginx等的启动而运行的,这里以Apache为例简要梳理下流程:

Swoole生命周期_第2张图片
PHP中客户端和服务器的交互
  1. PHP通过mod_php.so扩展和Apache建立联系,具体来说是SAPI服务器应用程序编程接口。

当Apache服务器启动后,PHP解释程序也随之启动,PHP启动的过程分为两步:

  • 初始化环境变量,这些环境变量将在SAPI生命周期中发生作用。
    PHP解释程序启动后,会调用各个扩展的MINIT方法即“模块初始化”,从而使扩展切换到可用状态。MINIT指的是,每个扩展模块都定义了一组函数、类库等用于处理其它请求。
  • 生成只针对当前请求的变量设置
    当客户端的请求发生时,SAPI层将控制权交给PHP层。于是,PHP设置了用于回复本次请求所需的环境变量,用来存放执行过程中产生的变量名和值。PHP调用各个扩展模块的RINIT方法即请求初始化。经典的案例使Session模块的RINIT方法,如果在php.ini中启用了Session扩展模块,那么在调用该模块的RINIT时就会初始化$_SESSION全局变量,并将相关内容读取。RINIT方法可看作是一个准备过程,在程序执行之间就会自动启动。

如同PHP启动一样,PHP的关闭也分为两个步骤

  • 一旦脚本执行完毕,无论是执行到文件末尾还是使用exitdie函数中止。PHP都会启动清理程序,清理程序会按顺序调用各个扩展模块的RSHUTDOWN方法,RSHUTDOWN方法用来清理程序运行时产生的符号表,也就是对每个变量调用unset函数。
  • 当所有的请求都处理完毕后,SAPI也准备关闭了。此时,PHP会调用每个扩展模块的MSHUTDOWN方法,这是各个扩展模块最后一次释放内存的机会。
  1. PHP中共有三个模块:PHP内核、Zend引擎、扩展层
Swoole生命周期_第3张图片
PHP核心
  • PHP内核:用来处理请求、文件流、错误处理等相关操作
  • Zend引擎:将PHP源文件转换成机器语言,并在Zend虚拟机上运行。
  • 扩展层:是一组函数、类库和流

PHP使用这个三个模块来执行特定的操作,如使用MySQL扩展来连接MySQL数据。

  1. 当Zend引擎执行程序时可能会需要连接若干扩展,此时Zend引擎会将控制权交给扩展,等处理完特定任务后再返还。
  2. Zend引擎将运行结果返回给PHP内核,PHP内核将结果传递给SAPI,最终通过Web服务器输出到浏览器。

PHP脚本运行流程

PHP作为Swoole的宿主,下图是以CLI命令行下执行一个PHP脚本文件时的完整流程:

Swoole生命周期_第4张图片
PHP生命周期

SAPI是PHP给外部环境执行PHP内核提供的统一接口,常见有三种:CLI、PHP-FPM、MOD_PHP。

以PHP-FPM为例,将PHP运行周期的关键步骤提取:

Swoole生命周期_第5张图片
PHP-FPM
  1. 初始化
    PHP引擎初始化公用配置,读取.ini配置文件,加载zend引擎。

  2. MINIT
    执行PHP各个扩展模块的MINIT(模块初始化)方法后,常驻在PHP-FPM进程中,等待处理请求。

  3. RINIT
    当请求过来后,调用PHP各个扩展模块的RINIT(请求初始化)方法进行请求内数据的初始化,如超全局变量和模块数据的初始化等操作。

  4. 执行PHP脚本
    加载PHP脚本文件,进行词法分析、语法分析、生成Opcode中间代码,然后交给Zend虚拟机,暂存执行结果。


    Swoole生命周期_第6张图片
    解释型语言PHP的执行流程
  5. RSHUTDOWN
    在结果返回给PHP-FPM之前,会调用PHP各个扩展模块的RSHUTDOWN(请求关闭)方法进行数据的回收,Zend虚拟机会关闭打开的数据流,进行内存释放等操作,然后把暂存的执行结果flush输出。

  6. MSHUTDOWN
    当重启PHP-FPM时会调用PHP各个扩展模块的MSHUTDOWN(模块关闭)方法,执行关闭Zend引擎等操作。

通过以上流程可以发现PHP-FPM中每个请求都是在执行第3~5步,Opcode缓存是将第4步的词法分析、语法分析、生成Opcode中间代码等几个操作给缓存起来,从而达到加速的目的。

Swoole生命周期_第7张图片
Opcode

既然每个请求都是独立的,那么能不能进行数据共享呢?由于在MINIT模块初始化时数据是常驻在PHP-FPM进程中的,所有是可以实现的,例如比较典型的.ini配置文件是放在这一步的。另外每个请求都能够独立释放内存,总体上是安全的,但也是有问题的,很有可能在扩展层就存在内存泄漏。所以PHP-FPM提供max_request来重启PHP-FPM,达到完全释放内存的目的。

Swoole的生命周期

分析了PHP的基本执行流程后,Swoole是在哪一步执行的呢?首先,Swoole运行有个前提条件:必须在CLI命令行模式下执行。Swoole在PHP执行流程的第4步执行PHP脚本时就接管了PHP,进入了Swoole的生命周期。

Swoole的生命周期以多进程模式为例,具体流程如下:

Swoole生命周期_第8张图片
Swoole执行流程
  1. 初始化
    创建Manager管理进程,创建Worker工作子进程,监听所有TCP/UDP端口,监听定时器Timer
  2. onStart
    onStart回调函数是在Master主进程中执行的,和Worker工作子进程的onWorkStart是并行的,并没有先后之分。在此回调函数中强烈要求只做Log记录和进程名设置操作,不要做业务逻辑。因为业务逻辑代码的错误将直接导致Master主进程Crash崩溃,进而让整个Swoole服务器无法对外提供服务。
  3. onReceive
    客户端请求的数据到达时会调用onReceive函数,进行业务逻辑处理输出结果。客户端发送的多次请求,服务端是可以一次性接收的,所以会发现一个问题是onReceive接收的数据会非常大。
  4. onWorkerStop
    Worker工作子进程退出时回调onWorkerStop函数。
  5. onShutDown
    Swoole服务停止时回调onShutDown函数,然后继续PHP-FPM的第5~6步,最后退出PHP的生命周期。

你可能感兴趣的:(Swoole生命周期)