图解
Nginx
nginx是目前较流行的web server
CGI
原先web server只能处理html等静态资源,后来出现了CGI协议,通过这个协议,开发者可以使用任何语言处理web server发来的请求,如php python nodejs等,理论上支持cgi的语言程序都可以,qzone早期的服务端版本就是c开发的cgi程序。
FastCGI
FastCGI,顾名思义为更快的 CGI,由于CGI每处理一个请求都要fork一个进程,随着互联网的发展,这种低效的方式已经不能满足需求,于是一个进程可处理多个请求的FastCGI就诞生了.
Php-fpm
php-fpm是 FastCGI 的实现,并提供了进程管理的功能,包含master 和 worker 两种进程。
master 创建并监听socket,fork多个woker进程,通过共享内存获取worker的状态,进而通过信号控制worker进程
worker 自由accept cgi请求,
master通过共享内存获取worker进程的信息,比如worker进程当前状态、已处理请求数等,当master进程要杀掉一个worker进程时则通过发送信号的方式通知worker进程。
网上很多php-fpm的文章都说master监听端口,然后再分配给worker处理,这个是不正确的,fpm的master进程与worker进程之间不会直接进行通信,worker 自由accept cgi请求。
fpm其实可以同时监听多个端口,每个端口对应一个worker pool,而每个pool下对应多个worker进程,这样不同业务可以用不同的woker pool处理。
再看看php源码中是如何处理cgi请求的
等待请求: worker进程阻塞在fcgi_accept_request()等待请求
解析请求: fastcgi请求到达后被worker接收,然后开始接收并解析请求数据,直到request数据完全到
请求初始化: 执行php_request_startup(),此阶段会调用每个扩展的:PHP_RINIT_FUNCTION()
编译、执行: 由php_execute_script()完成PHP脚本的编译、执行(这一步就是我们执行我们写的php代码了)
关闭请求: 请求完成后执行php_request_shutdown(),此阶段会调用每个扩展的:PHP_RSHUTDOWN_FUNCTION(),然后进入步骤1
fpm进程管理
fpm进程管理有3种方式
static: 在启动时master按照pm.max_children配置fork出相应数量的worker进程,即保持worker进程数不变
dynamic: 动态进程管理,在fpm启动时按照pm.start_servers初始化一定数量的worker,运行期间如果master发现空闲worker数低于pm.min_spare_servers配置数(请求比较多,worker处理不过来了)则会fork worker进程,但总的worker数不能超过pm.max_children,如果master发现空闲worker数超过了pm.max_spare_servers(闲着的worker太多了)则会杀掉一些worker,避免占用过多资源,master通过这4个值来控制worker数
ondemand: 这种方式一般很少用,在启动时不分配worker进程,等到有请求了后再通知master进程fork worker进程,总的worker数不超过pm.max_children,处理完成后worker进程不会立即退出,当空闲时间超过pm.process_idle_timeout后再退出
fpm 超时设置
在php-fpm.conf中有一个request_terminate_timeout的配置,如果worker处理一个请求的总时长超过了这个值,那么master将会向此worker进程发送kill -TERM信号杀掉worker进程,默认值为0表示关闭此机制,另外fpm中slow log也是在这里完成的。
常见问题
502
1.php-fpm.conf中request_terminate_timeout,如果超过这个时间,脚本停止执行,worker进程也会退出,这是nginx就会返回502,,可以优化worker处理速度解决
2. 没有空闲的worker去接受cgi请求,也会返回502,这时可以通过调整worker数量来解决
504
nginx 超时时间小于php超时时间导致
https://github.com/pangudashu/php7-internal/blob/master/1/fpm.md