php-fpm的配置与应用指南[推荐]

一、什么是php-fpm

PHP-FPM  全程是 FastCGI Process Manager (FastCGI进程管理器),对于PHP 5.3.3之前的php来说,是一个补丁包 ,旨在将FastCGI进程管理整合进PHP包中。如果你使用的是PHP5.3.3之前的PHP的话,就必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用。

从PHP 5.4 RC2开始,php-fpm已经转正了,不再被php团队标注为EXPERIMENTAL(实验性的东西)集成到php的发行版本中 。

相对Spawn-FCGI,PHP-FPM在CPU和内存方面的控制都更胜一筹,而且前者很容易崩溃,必须用crontab进行监控,而PHP-FPM则没有这种烦恼。PHP5.3.3已经集成php-fpm了,不再是第三方的包了。PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置,比spawn-fcgi具有更多优点,所以被PHP官方收录了。在./configure的时候带 –enable-fpm参数即可开启PHP-FPM。

参考文章:CGI、FastCGI、PHP-CGI、PHP-FPM的联系与区别

二、fpm工作流程

fpm启动后会先读php.ini,然后再读相应的conf配置文件,conf配置可以覆盖php.ini的配置。启动fpm之后,会创建一个master进程,监听9000端口(可配置),master进程又会根据fpm.conf/www.conf去创建若干子进程,子进程用于处理实际的业务。当有客户端(比如nginx)来连接9000端口时,空闲子进程会自己去accept,如果子进程全部处于忙碌状态,新进的待accept的连接会被master放进队列里,等待fpm子进程空闲;这个存放待accept的半连接的队列有多长,由 listen.backlog 配置。

三、php-fpm配置

注意:本人安装php7的目录是/usr/local/php7

pid = run/php-fpm.pid

默认是目录前缀 /usr/local/php7/var,例如:pid = run/php-fpm.pid ,则完整的路径是/usr/local/php7/var/run/php-fpm.pid,这个完整的路径也是默认的路径。

error_log = /var/log/php-fpm/error.log

默认是目录前缀 /usr/local/php7/var,默认值:log/php-fpm.log,完整的路径 /usr/local/php7/var/log/php-fpm.log

syslog.facility = daemon

将日志写入系统Log,参考文章:Haproxy中的log的设置原理解析,在Linux中的消息设备有

auth:             用户授权
authpriv:         授权和安全
cron:             计划任务
daemon:           系统守护进程
kern:             与内核有关的信息
lpr                与打印服务有关的信息
mail               与电子邮件有关的信息
news               来自新闻服务器的信息
syslog             由syslog生成的信息
user               用户的程序生成的信息,默认
uucp               由uucp生成的信息
local0~7           用来定义本地策略

syslog.ident = php-fpm

可以参考文章:Haproxy中的Log的相关配置详解,文章提到的 log-send-hostname,log-tag的含义是一样的,只是一个标志。

log_level = notice

日志级别,默认:notice,可选值alert, error, warning, notice, debug。对 syslog.facility 也同样适用。

emergency_restart_threshold = 0
emergency_restart_interval = 0

这2个配合适用,如果在 emergency_restart_interval 此参数设置的时间内,出现SIGSEGV或SIGBUS的子进程数超过 emergency_restart_threshold 参数设置的值,那么fpm就会优雅的重启,值是0表示off这个功能,可用的单位有:s 秒,m 分,h 时,d 天。例如:

emergency_restart_threshold = 60(建议值)
emergency_restart_interval = 60(默认单位s)

 process_control_timeout = 0

设置子进程接受主进程复用信号的超时时间. 可用单位: s(秒), m(分), h(小时), 或者 d(天) 默认单位: s(秒). 默认值: 0。不太好理解吧,看下面摘抄的一段文字:

先来简单谈谈PHP请求处理过程吧。
Nginx与PHP的交互依赖于CGI接口,因为两者都实现了CGI接口,所以Nginx可以把收到的请求交给PHP,并从PHP获
得相应的结果回传给客户端。

最基本的CGI实现是每次请求都新建一个PHP进程,处理完成后关闭进程,这种方式会消耗很多的资源在进程的启动和关
闭上,所以效率并不高。

进而出现了FastCGI这种实现方式,也就是启动一个进程后让它处理多个请求再关闭,这种方式就是解决每次请求都打开
和关闭进程的消耗的。但FastCGI有个缺点,就是因为一个进程只能同时处理一个请求,如果同时收到多个请求,它们
只能排队等待FastCGI进程的处理。

解决FastCGI只能同时处理一个请求的方式很简单,就是开启多个FastCGI进程。不过开启多个FastCGI进程的就存在
对这些进程的管理问题,比如究竟要开多少个进程,怎么根据需要分配请求到这些进程上等等。而PHP-FPM就是这样一个
管理FastCGI进程的管理程序。Nginx先将请求传递给PHP-FPM,再由PHP-FPM选择合适的FastCGI处理进程进行处理。

在PHP-FPM将请求传递给FastCGI处理进程的时候,就涉及到进程复用了。原则上,PHP-FPM会选择空闲的FastCGI
进程去处理请求,在处理之前,PHP-FPM会发送进程复用信号给FastCGI进程,用来让FastCGI进程准备好接受请求并
处理。但是,FastCGI进程并不总是能够处理请求,也就是不能够响应进程复用信号(比如说出现假死的情况),所以
这个参数就表示了PHP-FPM留给FastCGI进程多久时间去响应进程复用信号,如果超时了,PHP-FPM会选择其他的方式
(例如使用其他的FastCGI进程)去处理请求。

process.max = 128

当动态管理子进程时,fpm最多能fork多少个进程,0表示无限制,这是所有进程池能启动子进程的总和,谨慎使用。

process.priority =  -19

设置子进程的优先级,在master进程以root用户启动时有效;如果没有设置,子进程会继承master进程的优先级,值范围-19(最高)到20(最低),默认不设置。

daemonize = yes

不解释,哈哈

rlimit_files = 1024

设置master进程最多能打开的文件,默认为系统的值。

rlimit_core = 0

master进程核心rlimit限制值;可选unlimited或>=0的整数,默认为系统的值。

events.mechanism = epoll

事件处理机制,默认自动检测,可选值:select,poll,epoll(linux>=2.5.44),kqueue,/dev/poll,port

systemd_interval = 10

当fpm被设置为系统服务时,多久向服务器报告一次状态,单位有s,m,h ,默认单位秒,默认值10

*************************************************************************************************************
* 下面是在 php-fpm.d/www.conf 中的配置                                                                                     *
*************************************************************************************************************

prefix = /path/to/pools/$pool

前缀设置,可用于,’access.log’,’slowlog’,’listen’ (unixsocket), ‘chroot’, ‘chdir’, ‘php_values’,  ‘php_admin_values’

user = nobody
group = nobody

php-fpm 的 work 进程的用户和用户组。

listen = 127.0.0.1:9000

监听的ip和端口,也可以使用socket,例如:listen=/path/to/unix/socket

listen.backlog = 511

未accept处理的socket队列大小,-1 on FreeBSD and OpenBSD,其他平台默认511,高并发时重要,合理设置会及时处理排队的请求;太大会积压太多,处理完后nginx在前面都等超时断开这个和fpm的socket连接了,就杯具了。不要用-1,建议1024以上,最好是2的幂值。

  • 一个池共用一个backlog队列,所有的池进程都去这个队列里accept连接。
  • 最大数量受限于系统配置 cat /proc/sys/net/core/somaxconn,系统配置修改:vim /etc/sysctl.conf,增加 net.core.somaxconn = 2000 则最大为2000,然后php最大的backlog可以到2000。

参考文章:http://www.tuicool.com/articles/NNVb2iY

listen.owner = nobody
listen.group = nobody
listen.mode = 0660

用socket连接方式时,指定拥有unix socket权限的用户,默认和运行的用户一样,默认也是0660;用tcp连接可以注释掉.

listen.acl_users =
listen.acl_groups =

这2个暂时待定。

listen.allowed_clients = 127.0.0.1

用socket连接方式时,该设置才生效,多个IP用,分隔,默认是 any

process.priority = -19

池进程的权限,同样要master进程是root用户才有效,和全局那个一样,不设置的话会继承master进程的优先级。

pm = dynamic

启动时子进程管理方式,可选值:static(启动时创建指定个数), dynamic(启动时根据情况创建,至少有一个), ondemand(启动时不创建子进程,有需求才创建)

pm.max_children = 5 (三种方式都需要配置)

该池同时最多存在5个进程, 三种管理方式都要配置

pm.start_servers = 2 (dynamic方式有效)

fpm启动时创建2个子进程,只适用动态dynamic管理方式

pm.min_spare_servers = 1 (dynamic方式有效)

服务器闲置时最少保持1个子进程,不够这个数就会创建,只适用动态dynamic管理方式

pm.max_spare_servers = 3 (dynamic方式有效)

服务器闲置时最多要有几个,多了会kill,只适用动态dynamic管理方式

pm.process_idle_timeout = 10s (ondemand方式有效)

子进程闲置10s后就会被杀掉

pm.max_requests = 500

每个子进程最大处理500请求就被回收,可防止内存泄露。当子进程达到这个值后,会kill这个子进程,fork新的子进程。

pm.status_path = /status

php-fpm和nginx一样,内建了个状态页,可以通过该状态页了解监控php-fpm的状态,详细的使用可以参考这里:开启php-fpm状态页及pm.status_path状态详解

ping.path = /ping

FPM监控页面的ping网址. 如果没有设置, 则无法访问ping页面. 该页面用于外部检测FPM是否存活并且可以响应请求. 请注意必须以斜线开头 (/)

ping.response = pong

用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.

access.log = log/$pool.access.log

访问文件日志,前缀见prefix,没啥用处,比如yii2每次都记录访问index.php,只是记录真实的PHP文件。

access.format = “%R – %u %t \”%m %r%Q%q\” %s %f %{mili}d %{kilo}M %C%%”

访问日志格式

slowlog = log/$pool.log.slow

PHP文件执行过慢的日志,会准确的记录具体哪一行代码太慢,这个非常有用,在设置了时间时生效。

request_slowlog_timeout = 1s

超过这个运行时间就会写慢日志,单位有s,m,h ,默认单位秒,默认值0,表示不记录慢日志。

request_terminate_timeout = 0

单个请求的超时时间,有时候php.ini设置的最大执行时间(max_execution_time)未生效,这个就会来干掉那个执行太久的请求。单位有s,m,h ,默认单位秒,默认值0,表示关闭该功能。

rlimit_files = 1024
rlimit_core = 0

这两个见上面的全局设置。

chroot =

路径必须是绝对路径,改变子进程的跟目录,可以把进程对文件系统的读写与实际的操作系统文件系统隔离,对安全有好处。

chdir = /var/www

改变当前工作目录,可以用相对路径,默认是当前目录或者chroot

catch_workers_output = yes

重定向标准输出stdout和标准错误stderr到主错误日志,如果不设置,这两个日志就会定向到/dev/null,在高负载情况下,这个配置会引起页面延迟几毫秒,默认不开启。

clear_env = no

创建work进程时是否清除环境变量,如果是yes,那么该子进程 getenv() 就访问不到 $_ENV 和$_SERVER 了。

security.limit_extensions = .php .php3 .php4 .php5 .php7

为了安全,限制能执行的脚本后缀

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

通过这种方式设置环境变量, php中通过 $_SERVER 获取到环境变量。

php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.www.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M

为当前池指定另外的 php.ini 配置,比如指定当前池的错误日志写在哪个地方

  • php_value/php_flag 可以设置php.ini的内容,可以被ini_set覆盖
  • php_admin_value/php_admin_flag 这个同上,但是不会被ini_set覆盖。
  • 其中flag设置的,值只能是on, off, 1, 0, true, false, yes or no,其他类型的值需要用value。
  • 这种方法设置 `disable_functions` 和 `disable_classes` 时,不会覆盖 php.ini 的设置,只会追加。

Tips 1:PHP配置值通过 php_value 或者 php_flag 设置,并且会覆盖以前的值。请注意 disable_functions 或者 disable_classes 在 php.ini 之中定义的值不会被覆盖掉,但是会将新的设置附加在原有值的后面。
使用 php_admin_value 或者 php_admin_flag 定义的值,不能被 PHP 代码中的 ini_set() 覆盖。

可以参考php的官网解释:http://php.net/manual/zh/install.fpm.configuration.php

三、nginx 通过 unixsock 与 php-fpm 通信

适用场景:nginx和php-fpm在同一台服务器上,这时可以直接用unixsocket进程间通信,不走tcp端口通信,可以节约创建连接的时间,从而提高性能。

  1. 设置php-fpm的listen为/opt/remi/php56/root/var/run/php-fpm/php567-fpm.sock(可以用相对路径),然后重启fpm就会自动创建该php567-fpm.sock文件
  2. nginx的fastcgi_pass参数修改为 unix:/opt/remi/php56/root/var/run/php-fpm/php567-fpm.sock; 通过php567-fpm.sock文件去和fpm通信,需要保证该 php567-fpm.sock 文件 nginx 有权限访问。

Tips 2:sock文件随便创建到哪里都可以,只要fpm有权限在那个目录里写文件,nginx有权限去读就可以。tcp连接会更稳定,因为有tcp协议保证数据的正确性,但是sock有更少的数据拷贝和上下文切换,更少的资源占用。不过只能在nginx和fpm在同一台机器上才能用sock。

Tips 3:但本人测试中发现,sock文件必需使用 777,原因日后补充。。。

四、fpm进程状态监控

1、nginx配置:遇到 status 的请求,直接转发给php

location = /status {
    fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
}

Tips 3:关于nginx中的location可以参考:Nginx location匹配规则

2、fpm配置:pm.status_path = /status

3、然后重新fpm和nginx,在浏览器里访问就能看到了:
默认以 text/plain 展示结果,可以传参数 ?json/html/xml 分别得到json等格式的结果;参数full可以查看每个子进程的明细

381128-20170112145855103-1663826983

pool 进程池名称

  • process manager 进程管理方式
  • start time 进程什么时候启动的
  • start since 进程已经运行了多少秒
  • accepted conn 该池总共accept了多少连接
  • listen queue 等待accept的连接的数量
  • max listen queue fpm启动后,历史最高等待accept的连接的数量
  • listen queue len 配置的监听队列最大长度 受限于`listen.backlog`和系统`cat /proc/sys/net/core/somaxconn`,两者中取最小值
  • idle processes 闲置的进程数
  • active process 正在工作的进程数(加上限制的,就是总的子进程数)
  • total processes 总的子进程数量
  • max active processes fpm启动后,历史最多同时工作的进程数
  • max children reached 进程管理模式为 ‘dynamic’和 ‘ondemand’时,此数值是当子进程不够用时,master创建更多子进程的次数
  • slow requests 慢请求个数

full参数下

  • pid 子进程ID;
  • state 子进程状态(Idle, Running, …);
  • start time 子进程启动的时间;
  • start since 子进程启动后运行了多少秒;
  • requests 当前子进程一共处理了多少个请求;
  • request duration 请求耗费的纳秒数;
  • request method 请求方法 (GET, POST, …);
  • request URI 请求参数;
  • content length POST请求时,请求的内容长度;
  • user – the user (PHP_AUTH_USER) (or ‘-‘ if not set);
  • script 请求的哪个php文件;
  • last request cpu 上次请求耗费的cpu资源
  • last request memory 上次请求耗费的内存峰值
  • 如果进程是闲置状态,那这些信息记录的就是上次请求的相关数据,否则就是当前本次请求的相关数据。

六、backlog配置问题

一个fpm子进程在同一时间只能处理一个请求,如果,backlog设置得过大,nginx之类的客户端发起的请求一直没有fpm子进程进行accept,nginx就会直接断掉这个连接,等fpm忙过来了再去accept的时候,就会发现断开了,于是报错。backlog设置得过小,访问量大时fpm子进程全部处于忙碌状态,backlog也塞满了,就会拒绝新的连接,此时nginx再请求,就会直接被拒。所以需要合理的设置backlog参数。

七、php-fpm的启动配置、启动、关闭、重启

参考文章:php7的安装以及编译中的错误

参考文章:CGI、FastCGI、PHP-CGI、PHP-FPM的联系与区别

相关文章:

CGI、FastCGI、PHP-CGI、PHP-FPM的联系与区别

CGI、FastCGI和PHP-FPM关系图解[转]

php-fpm的配置详解

php7的安装以及编译中的错误

php-fpm的配置与应用指南[推荐]》上有1条评论

  1. Pingback引用通告: php7的安装以及编译中的错误 | 精彩每一天

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>