乐趣区

深入了解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 长连接

退出移动版