zoco

深入浅出FastCGI和php Fpm

2017-06-05


先看个图,标准的PHP单进程CLI和CGI生命周期。php进程启动,需要zend core、Module的Init(MINIT)、Request 的Init(RINIT) 这样的。一个进程只服务一次命令行或HTTP请求,就退出。

NukKv6.png

而FastCGI/php-fpm 就是改造后的多进程的 CGI,类似于资源池,预先启动 100个 php-fpm 进程,提前MINT,nginx的请求来了,直接进入 RINIT -> RSHUTDOWN 循环。请求结束,进程不退出,一个进程至少服务上万次请求才退出。

为什么一定要退出?怕RINIT->RSHUTDOWN循环,有哪个代码写的不好,变量一直没释放,内存泄露GC又回收不了。php-fpm里的pm.max_requests配置就是设置RINT循环多少次,退出进程。

再来看几个 TSF、swoole、workerman、php-pm,都是 php 启动cli进程,用php管理子进程,php解析HTTP协议。

生命周期连RINIT->MINIT循环都省了,没写在类属性里的变量,裸写的变量都是进程级全局变量,比php-fpm下的$_GET、$_POST、$_SERVER、$_SESSION、$_COOKIE这些全局变量范围还大,是进程级的。意味着你写了个a.php,里面定义了$a=1;赋值之后,下次请求过来,只要正好分配到了这个进程,依然还能取到普通定义的$a变量。

这意味着什么?像Laravel里的$app这些变量,只要写在最外面,因为没有触发RSHUTDOWN,又没有主动unset,GC引用计数器一直大于0,变量不会消失。

那怎么解决每次请求$_GET和$_POST不一样的问题?这些swoole、workerman进程管理器自己实现了小型化的INIT->SHUTDOWN过程,维护一些引用计数呗,自己的a.php完成后,这种框架帮你unset($_GET)。

问题来了,稳定不稳定?swoole、workman框架本身稳定,但因为完全改变了php生命周期,业务开发人员不熟悉,一不小心写了global、static这样的变量,全局用了,内存越占越大,崩溃。又或者写了个exit,把整个进程exit而不是requestext了。