深入了解SAPI
一、SAPI比较
1. SAPI
服务器应用程序编程接口,就是服务器与编程语言之间交互的接口。比如Linux命令行执行一段PHP代码,其实是Linux shell通过PHP SAPI传入一组参数,zend引擎执行后返回给shell。在PHP生命周期的各个阶段,一些与服务相关的操作都是通过SAPI接口实现。
php_sapi_name()可以查看当前SAPI接口的类型。 如 cli(php -r "echo php_sapi_name();")、fpm-fcgi等
2. PHP运行和加载的4个阶段
①Minit 模块初始化阶段,可以初始化php扩展、类库的内部变量、注册常量,定义模块使用的类等。
②Rinit 请求初始化阶段,在模块初始化并激活后,会创建PHP运行环境,初始化本次请求所需的环境变量,比如 $_SERVER,$_SESSION
。
③Rshutdown 请求关闭阶段,执行最后的清理工作,释放所有处理本次请求的资源(申请的变量)。请求完成可能是执行到脚本完成,也可能是调用die()或exit()函数完成
④Mshutdown 模块回收阶段,用于关闭自己的内核子系统,释放没存。
3. SAPI 5种运行模式
①单进程模式(CLI,CGI),每次执行PHP脚本,都会执行第二部分讲的四个INT和Shutdown事件。当用户请求数量非常多时,会大量挤占系统的资源如内存,CPU时间等,造成系统开销很大
②多进程模式(Apache下的prefork MPM模式),会fork很多子进程,每个子进程拥有自己独立的进程地址空间,在一个子进程中,PHP的生命周期是调用MINT启动后,执行多次请求(RINT/RSHUTDOWN),在Apache关闭或进程结束后,才会调用MSHUTDOWN进行回收阶段。
多进程模型中,每个子进程都是独立运行,没有代码和数据共享,因此一个子进程终止退出和重新生成,不会影响其他子进程的稳定。
③多线程模式(Apache2的Worker MPM),在一个进程下创建多个线程,在同一个进程地址空间执行
④fastCGI模式,nginx+php-fpm就是这个模式,fast-cgi是CGI的升级版本,FastCGI可以看成是一个常驻型的CGI,它可以一直执行着,运行后可以fork多个进程,不用花费时间动态Fork子进程。也不需要每次请求都调用MINT/MSHUTDOWN。
⑤内嵌模式,允许在C/C++语言中调用PHP提供的函数,运行模式和CGI一样,执行4个阶段
二、php-fpm运行原理
- CGI:是个协议,服务器发起请求,传给PHP解析器,传递哪些数据,以什么格式,由CGI决定
- fastcgi:是个协议,提高CGI性能的,不用每次都去初始化,进程不够用,会预先启动几个进程,进程空闲太多了也会停掉一些,fastCGI对进程的管理,提高性能,节约了资源
- php-fpm:实现fastCGI协议的程序,被PHP官方收了,也提供了进程管理功能,进程包含 master 进程和 worker 进程两种进程。 master 进程只有一个,负责监听端口分发请求,接收来自 Web Server 的请求,而 worker 进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。
- php-cgi:cgi解释器进程
FastCGI的工作原理:
- Web Server启动时载入FastCGI进程管理器
- FastCGI进程管理器自身初始化,启动多个CGI解释器(可见多个php-cgi)并等待来自Web Server的连接
- 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web Server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi
- FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告知处理完成。FastCGI子进程接着等待并处理来自FastCGI继承管理器的下一个连接
使用FastCGI,系统开销小。另外,对于数据库和Memcache的持续连接可以工作。
数据库短连接connect:请求关闭阶段,释放请求所用的资源,数据库连接句柄也会被释放数据库长连接pconnect:请求关闭后,PHP会收留此次连接,即使主动关闭也不会关闭而是收留,下次有打开相同连接的请求时,PHP直接把收留的句柄拿出来,省去建立连接的过程。
php-fpm实现长连接也需要配合数据库一些配置,一个进程收留一个连接,数据库连接的数量就是子进程数量,所以数据库允许连接数就要大于子进程数。
三、php-fpm进程管理的三种模式
php-fpm支持三种运行模式,分别为static、ondemand、dynamic,默认为dynamic 。
- static : 静态模式,启动时分配固定的worker进程。只需要考虑max_children的数量,数量取决于cpu的个数和应用的响应时间。
- ondemand: 按需分配,启动时不分配任何进程,当收到用户请求时才启动进程。 master进程检查work进程的数量是否受限,是否有空闲的work进程,没有就新建work进程。在大流量的系统上master进程会变得繁忙,占用系统cpu资源,不适合大流量环境的部署。
- dynamic: 动态模式,启动时分配固定的进程。伴随着请求数增加,在设定的浮动范围调整worker进程。
pm = dynamic //动态进程管理,对于专用服务器,可以设置为static,静态一次性启动最大子进程数,不会变化。 pm.max_children = 50 //最大子进程数,ps aux可以查看 pm.start_servers = 20 //启动服务时会启动的进程数 pm.min_spare_servers = 5 //保证空闲子进程数的最小值,如果空闲进程小于这个值,php-fpm服务会创建新的子进程。 pm.max_spare_servers = 35 //保证空闲子进程数的最大值,如果空闲进程高于这个值,就进行清理。 pm.max_requests = 500 //定义一个子进程最多处理的请求数,达到这个值,进程自动退出。目的是为了控制内存溢出,使内存在一个可控范围内。但是如果设置的很小,有可能多个进程同时达到这个值,同时重启,就会导致PHP停止响应直到重启完毕。设置为0表示一直接受请求。
四、php-fpm慢日志
如果一个php网站可以访问,就是访问速度变慢了,可以通过php-fpm的慢执行日志,清晰的了解到php的脚本哪里执行时间长,它可以定位到具体的代码行
vim /usr/local/php/etc/php-fpm.d/www.conf request_slowlog_timeout = 1 //超时时间 slowlog = /usr/local/php/var/log/www-slow.log 重启php-fpm /etc/init.d/php-fpm reload
我在php文件中加了一行sleep(3);
,运行之后返回结果
参考文献
1、https://www.jianshu.com/p/c9a... php-fpm进程管理的三种模式
2、https://www.jb51.net/article/... SAPI的5种运行模式
3、http://blog.51cto.com/1260661... php-fpm慢日志
4、https://www.cnblogs.com/wpjam... php-fpm与mysql长连接