当前位置: 首页 > 工具软件 > PHP-FPM > 使用案例 >

PHP-FPM 配置文件详解

益清野
2023-12-01


说明

系统:macOS 10.14.6
PHP:homebrew 安装的 PHP8.0.20 (fpm-fcgi)

除了有 php-fpm.conf 配置文件外,通常还有其他的 *.conf 配置文件(也可以不要,直接在 php-fpm.conf 配置)用于配置进程池,不同的进程池可以用不同的用户执行,监听不同的端口,处理不同的任务;多个进程池共用一个全局配置。

关于路径问题,原文是这样说的:
All relative paths in this configuration file are relative to PHP’s install prefix (/usr/local/Cellar/php@8.0/8.0.20). This prefix can be dynamically changed by using the ‘-p’ argument from the command line.
“此配置文件中的所有相对路径都相对于 PHP 的安装前缀。 可以使用命令行中的“-p”参数动态更改此前缀。”。
通过 phpinfo() 看到编译参数 ‘–prefix=/usr/local/Cellar/php@8.0/8.0.20’ ‘–localstatedir=/usr/local/var’
所以我的环境下,prefix=/usr/local/Cellar/php@8.0/8.0.20。按照他的说法,如果我使用以下设置:

pid = run/php-fpm.pid
error_log = log/php-fpm.log

那么应该出现以下两个文件
/usr/local/Cellar/php@8.0/8.0.20/run/php-fpm.pid
/usr/local/Cellar/php@8.0/8.0.20/log/php-fpm.log
但实际出现的是以下两个文件
/usr/local/var/run/php-fpm.pid
/usr/local/var/log/php-fpm.log
也就是说这两个指令的相对地址是/usr/local/var(从结果上对应“–localstatedir”)。看原文说明也特别说明了他们的相对地址是 /usr/local/var:

; Pid file
; Note: the default prefix is /usr/local/var
; Default Value: none
pid = run/php-fpm.pid

; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /usr/local/var
; Default Value: log/php-fpm.log
error_log = log/php-fpm.log

不明白是上下文为什么会有这种冲突。难道这两个指令是相对于 localstatedir?不管是他的问题还是我理解的问题,涉及的路径的问题,最好还是直接使用完整路径,放在哪了清晰明了。


一、php-fpm.conf 文件

1.全局配置(Global Options)

pid = /usr/local/var/run/php8.0-fpm.pid
#fpm 主进程 pid 存放位置,进程会根据设置自动生成文件

error_log = /usr/local/var/log/php8/php-fpm.log
#错误日志存放位置,设置成本地文件即可,进程会根据设置自动生成文件
#若设置成"syslog",日志将发送给 syslogd。(syslogd 不熟悉可以无视)

针对 error_log = syslog  个人建议有明确需要再来关注这两个指令
;syslog.facility = daemon
#用于说明正在记录消息的程序是什么类型,
#syslogd 可以对不同类型的 facility(设备)信息采取不同的处理方式。
#当前环境默认:daemon(可能是因为我们通常是以守护进程的方式在运行 fpm)以下是可以被
#识别的值:
#kern     内核信息,首先通过 klogd 传递;
#user     用户进程;
#mail     邮件;
#daemon   后台进程;
#authpriv 授权信息;
#syslog   系统日志;
#lpr      打印信息;
#news     新闻组信息;
#uucp     由uucp生成的信息
#cron     计划和任务信息。
#mark     syslog 内部功能用于生成时间戳
#local0----local7   与自定义程序使用,例如使用 local5 做为 ssh 功能
#扩展阅读:https://blog.csdn.net/zyy617532750/article/details/74942090
;syslog.ident = php-fpm
#当启用了多割进程池,这一项负责区分出不同的进程池消息,所有有多个进程池配置时,此项的值应该也不同
#当前环境默认:php-fpm

;log_level = notice
#记录日志的级别:alert、error、warning、notice、debug。当前环境默认:notice

;log_limit = 1024
#单行字符数。如果该行超出限制,则换行。当前环境默认:1024。

;log_buffering = yes   重日志场景关注此项
#google 翻译:日志缓冲指定日志行是否被缓冲,这意味着该行是在单个写入操作中写入的。
#如果值为 false,则数据直接写入文件描述符。这是一个实验性的选项,可以在一些繁重的日志
#记录场景中潜在地提高日志记录性能和内存使用率。如果记录到 syslog,则忽略此选项,
#因为它必须始终被缓冲。
#当前环境默认:yes

;emergency_restart_threshold = 0
;emergency_restart_interval = 0
#表示在 emergency_restart_interval 所设置的时间内(如设置:60s)出现SIGSEGV
#或者SIGBUS错误的 php-cgi 进程数如果超过了 emergency_restart_threshold 个,
#php-fpm 就会优雅重启。这对于解决加速器共享内存中的意外损坏非常有用。
#这两个选项一般保持默认值。0 表示 “关闭该功能”。 当前环境默认: 0 (关闭)。

;process_control_timeout = 0
#设置子进程等待主进程对信号做出反应的超时时间。
#默认单位:s(秒)。 默认值:0(不限制超时时间)。

; process.max = 0
#允许 FPM 可 fork 出的进程的最大数。
#当开启了多个进程池并在多个进程池中使用动态 PM(下面有讲)时,
#用来限制全局进程数。谨慎使用。默认:0,没有限制

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

daemonize = yes
#设置 yes,FPM 将在后台运行;
#设置 no,FPM将在前台运行,此模式有助于调试时及时展示错误信息

当程序提示打开文件数量受到限制时,关注这两项。
在一些并发或多线程情况下,需要突破这个限制。
;rlimit_files = 1024
#设置 master 进程最多能打开的文件数。nginx.conf中也能看到相关指令。默认为系统的值。
;rlimit_core = 0
#设置 master 进程核心 rlimit 限制值;可选 unlimited 或 >=0 的整数,默认为系统的值。
#ulimit -n 和-u 可以查看 linux 的最大进程数和最大文件打开数。

;events.mechanism = epoll
#一直不知道干嘛的 默认自动检测
# Specify the event mechanism FPM will use. The following is available:
# - select     (any POSIX os)
# - poll       (any POSIX os)
# - epoll      (linux >= 2.5.44)
# - kqueue     (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
# - /dev/poll  (Solaris >= 7)
# - port       (Solaris >= 10)

;systemd_interval = 10
#当 fpm 被设置为系统服务时,多久向服务器报告一次运行报告,单位有s、m、h。
#默认单位s,默认值10。(原来程序也要打卡上班的)默认即可,不用管他。

2.进程池设置(Pool Definitions)

#在不同的监听端口和不同的管理选项下可以跑任意数量的池,并没有个数限制;
#进程池的名字用于 标记哪些属于本进程池进程的日志和统计数据。
#像 nginx 可以把不同的虚拟主机的配置写在自己的文件中然后再通过 include 引入一样
#多个进程池配置也可以单独写进不同的文件,引入文件时可以写相对路径,也可以写绝对路径
#默认只有 www.conf
include=/usr/local/etc/php/8.0/php-fpm.d/*.conf

当前环境下 include 引入的文件是 /usr/local/etc/php/8.0/php-fpm.d/www.conf 下文继续介绍 www.conf

二、www.conf 文件

1.进程池基本设置+监听设置

[www]
#启动一个名为'www'的进程池,这个值会写入$pool变量,可以在本文中任何指令中使用,
#需要使用进程池名称的地方,都可以直接使用$pool作为代替。

;prefix = /path/to/pools/$pool 使用相对路径时关注下
#本配置文件中的相对路径前缀 prefix,默认不设置,将使用全局默认 prefix
#一般我喜欢设置完整路径
#只影响下面的指令(如果它们设置的是相对路径的话):
# - 'access.log'
# - 'slowlog'
# - 'listen' (unixsocket)
# - 'chroot'
# - 'chdir'
# - 'php_values'
# - 'php_admin_values'

user = nobody
group = nobody
#设置 worker 进程启动时的 user 和 group,必须要设置 user,而 group 在未设置的情
#况下,默认使用 user 所在的 group,默认都是 nobody,一般系统中也会存在这个用户和组

listen = 127.0.0.1:9999
#监听的 ip 和端口号。
#可以的格式如下:
# 'ip.add.re.ss:port'    - 通过 a TCP socket 监听 IPv4:port
# '[ip:6:addr:ess]:port' - 通过 a TCP socket 监听 IPv6:port
# 'port'                 - 通过 a TCP socket 监听 以上所有地址类型
# '/path/to/unix/socket' - 通过 a unix socket 监听

;listen.backlog = 511       高并发时关注(注释是抄的,我没太理解)
#设置 listen(2) 函数的 backlog 参数值,默认: 511。
#未 accept 处理的 socket 队列大小,-1 on FreeBSD and OpenBSD,其他平台默认
#65535,高并发时重要,合理设置会及时处理排队的请求;太大会积压太多,处理完后 
#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://blog.chinaunix.net/uid-28541347-id-5748886.html

针对 unix socket 连接方式的设置
;listen.owner = nobody
;listen.group = nobody
;listen.mode = 0660
#用 unix socket 连接方式时,指定拥有 unix socket 权限的用户,
#默认和运行的用户一样;用 tcp 连接可以注释掉
;listen.acl_users =
;listen.acl_groups =
#当支持 POSIX 访问控制列表时,您可以使用这些选项设置它们,值是用逗号分隔的用户/组
#名称的列表。 设置后,listen.owner 和 listen.group 将被忽略
 
;listen.allowed_clients = 127.0.0.1
#设置允许连接 fpm 的地址,多个地址用逗号隔开,如果不配置,则默认任意地址都能来连。
默认:any,任何主机都可以连接。仅对 tcp socket 有意义。
# Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable 
# in the original PHP FCGI (5.2.2+).

2.process(干嘛的?)

; process.priority = -19       不理解优先级的用途,默认就好
#set nice(2) priority 参数。
#池进程的权限,同样要 master 进程是 root 用户才有效,和全局那个一样,
#不设置的话会继承 master 进程的优先级。默认不设置。
; process.dumpable = no         不知道实际用途,默认就好
#即使进程用户或组不同于主进程用户,也要设置进程可转储标志 (PR_SET_DUMPABLE prctl)。 
#它允许为池用户创建进程核心转储和 ptrace 进程。默认值:no


3.进程管理器(process manager,简称pm)

pm = dynamic
#决定进程管理器以哪种算法来控制进程数量,提供了三种算法:
#static  - 固定数量,数值由 pm.max_children 确定;
#dynamic - 子进程的数量是根据以下指令动态设置的。有了这个流程管理,总会有至少1个子进程:
#          pm.max_children      - 可以同时活跃的最大子进程数。
#          pm.start_servers     - fpm 启动时创建的子进程数量(就是初始值)
#          pm.min_spare_servers - 空闲子进程的最小值,低于这个值就会创建新的子进程
#          pm.max_spare_servers - 空闲子进程的最大值,高于这个值就会kill部分子进程
#ondemand - fpm 启动时不创建子进程. 有连接请求时才会创建子进程,涉及指令:
#             pm.max_children         - 可以同时活跃的最大子进程数。
#             pm.process_idle_timeout - 指定空闲进程空闲多久后被killed
#默认dynamic 小内存建议dynamic 8G以上建议static 因为创建和回收进程也是有开销的

#pm.max_children 等效于带有 mpm_prefork 的 ApacheMaxClients 指令。等效于原始
#PHP CGI 中的 PHP_FCGI_CHILDREN 环境变量。以下默认值基于没有太多资源的服务器。
pm.max_children = 5 #dynamic static ondemand
pm.start_servers = 2  #dynamic 
					  #计算公式:(min_spare_servers + max_spare_servers) / 2
pm.min_spare_servers = 1 #dynamic
pm.max_spare_servers = 3 #dynamic
;pm.process_idle_timeout = 10s; #ondemand 默认值10s 

;pm.max_requests = 500
#每个子进程最大处理500请求就被回收,可防止内存泄露。默认没有开启,进程永远不重启。
#等效于 PHP_FCGI_MAX_REQUESTS

4.FPM 运行状态页面(FPM status page)

非常有意思的功能(默认关闭状态),fpm 提供了获取进程运行状态的入口,并提供了一个静态页面来展示这些数据。文章结尾有设置参考

;pm.status_path = /status #负责开启或关闭 FPM status page
;pm.status_listen = 127.0.0.1:9001 #这是干嘛的 反正默认就好了

;ping.path = /ping
#FPM 监控页面的 ping 网址。 如果没有设置,则无法访问 ping 页面。该页面用于外部
#检测 FPM 是否存活并且可以响应请求。请注意必须以斜线开头 (/)。默认没有设置
;ping.response = pong
#用于定义 ping 请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本。
#默认值:pong。

5.日志和请求

;access.log = log/$pool.access.log
#类似于 nginx 的访问日志,fpm 也有访问日志,每次有请求过来都可以记录日志,默认关闭
;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 = 0  #超过指定时间的请求将被写进慢日志 默认0
;request_slowlog_trace_depth = 20 #慢日志堆栈信息深度 默认20

;request_terminate_timeout = 0
#设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的'max_execution_time'因为
#某些特殊原因没有中止运行的脚本有用. 设置为 '0' 表示 'Off'.当经常出现502错误时可以尝试
#更改此选项。默认为0

;request_terminate_timeout_track_finished = no
# 在应用程序调用 'fastcgi_finish_request' 或应用程序完成并调用关闭函数(通过
# register_shutdown_function 注册)后,不使用 'request_terminate_timeout' ini 
# 选项设置的超时。 即使在这种情况下,此选项也将启用无条件应用超时限制。 默认no关闭

#和上面含义一样 按照上下文的意思 只限制当前线程池 默认系统默认值
;rlimit_files = 1024
;rlimit_core = 0

6.其他

;chroot =
#启动时的chroot目录. 所定义的目录需要是绝对路径. 如果没有设置, 则chroot不被使用.
#默认没有设置
;chdir = /var/www
#设置启动目录,启动时会自动chdir到该目录. 所定义的目录需要是绝对路径. 默认值: 当前目录,
#或者/目录(chroot时)
#注意:chroot和chdir是两个系统命令,开启这两项时,php-fpm在启动时会执行这两个命令,而参数值就是此处设置的值,至于实际用途不是很理解,暂时保持默认好了。

;catch_workers_output = yes
#重定向运行过程中的stdout和stderr到主要的错误日志文件中. 如果没有设置, stdout 
#和 stderr 将会根据FastCGI的规则被重定向到 /dev/null . 默认值: no.
;decorate_workers_output = yes
#使用前缀和后缀装饰工作输出,其中包含有关写入日志的子节点的信息,以及是否使用了 stdout 或 
#stderr 以及日志级别和时间。 仅当 catch_workers_output 为 yes 时才使用此选项。 
#设置为“no”将输出写入 stdout 或 stderr 的数据。

;clear_env = no #清理环境 默认yes 默认即可
;security.limit_extensions = .php .php3 .php4 .php5 .php7
#设置fpm执行解析的扩展名 默认 .php

#传递环境变量,如 LD_LIBRARY_PATH。 所有 $VARIABLEs 都取自当前环境。
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp

#php.ini 的附加设置,只应用于这个进程池。这些设置会覆盖之前在 php.ini 中定义的值。
#此处若定义 disable_functions 或者 disable_classes ,会将新的设置附加在原有值的后面。
#使用 php_admin_value 或者 php_admin_flag 定义的值,不能被 PHP 代码中的 ini_set() 覆盖。
;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


总结

1.初次安装时,需要更改或可以关注的配置项

pid = /usr/local/var/run/php8.0-fpm.pid
error_log = /usr/local/var/log/php8/php-fpm.log
log_level = notice
daemonize = yes
user = nobody
group = nobody
listen = 127.0.0.1:9999
listen.allowed_clients = ipaddress_1,ipaddress_2,127.0.0.1,...
pm = dynamic 同时关注下其他相关设置
pm.max_requests = 0 按需要选择是否开启

访问日志 默认关闭
access.log = log/$pool.access.log 按需要选择是否开启
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"

慢日志 默认关闭
slowlog = log/$pool.log.slow
request_slowlog_timeout = 15
request_slowlog_trace_depth = 20

2.到底选择 static 还数 dynamic?

一般原则是:动态适合小内存机器,灵活分配进程,省内存。静态适用于大内存机器,动态创建回收进程对服务器资源也是一种消耗。

如果你的内存很大,有8-20G,按照一个 php-fpm 进程 20M 算,100个就2G内存了,那就可以开启 static 模式。如果你的内存很小,比如才256M,那就要小心设置了,因为你的机器里面的其他的进程也算需要占用内存的,所以设置成 dynamic 是最好的,比如:pm.max_chindren = 8, 占用内存160M左右,而且可以随时变化,对于一般访问量的网站足够了。

文本出处

3.慢日志查询

我们有时候会经常饱受500,502问题困扰。当 Nginx 收到如上错误码时,可以确定后端 php-fpm 解析 php 出了某种问题,比如,执行错误,执行超时。
这个时候,我们是可以开启慢日志功能的。
slowlog = /usr/local/var/log/php-fpm.log.slow
request_slowlog_timeout = 15s
当一个请求该设置的超时时间15秒后,就会将对应的PHP调用堆栈信息完整写入到慢日志中。
php-fpm慢日志会记录下进程号,脚本名称,具体哪个文件哪行代码的哪个函数执行时间过长:
[21-Nov-2013 14:30:38] [pool www] pid 11877
script_filename = /usr/local/lnmp/nginx/html/www.quancha.cn/www/fyzb.php
[0xb70fb88c] file_get_contents() /usr/local/lnmp/nginx/html/www.quancha.cn/www/fyzb.php:2
通过日志,我们就可以知道第2行的 file_get_contents 函数有点问题,这样我们就能追踪问题了。

文本出处

4.nginx 通过 unix sock 与 php-fpm 通信

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

1、设置 php-fpm 的 listen 为 /you_path/php-fpm.sock,然后重启 fpm 就会自动创建该文件
2、nginx 的 fastcgi_pass 参数修改为 unix:/you_path/php-fpm.sock;通过 php-fpm.sock 文件去和 fpm 通信,需要保证该 nginx 有权限访问 php-fpm.sock 文件 。

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

5.启用 FPM status page

相关配置参考此处
另一处参考
注意:使用file://协议访问 status.html 时,要解决跨域问题

6.backlog 配置问题

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

大部分参数只要系统默认的就可以了,我们只需要知道几个比较重要的参数设置,什么时候用到可以回头查询相关说明

7.pm.max_children 与 request_terminate_timeout

在php-fpm的配置文件中,有两个指令非常重要,就是"pm.max_children" 和 “request_terminate_timeout”
第一个指令"pm.max_children" 确定了php-fpm的处理能力,原则上时越多越好,但这个是在内存足够打的前提下,每开启一个php-fpm进程要占用近30M左右的内存

如果请求访问较多,那么可能会出现502,504错误。对于502错误来说,属于繁忙进程而造成的,对于504来说,就是客户发送的请求在限定的时间内没有得到相应,过多的请求导致“504 Gateway Time-out”。这里也有可能是服务器带宽问题。

另外一个需要注意的指令"request_terminate_timeout",它决定php-fpm进程的连接/发送和读取的时间,如果设置过小很容易出现"502 Bad Gateway" 和 “504 Gateway Time-out”,默认为0,就是说没有启用,不加限制,但是这种设置前提是你的php-fpm足够健康,这个需要根据实际情况加以限定。

其他参考页 *php-fpm超时时间设置request_terminate_timeout分析

8.其他参考内容

一分钟了解PHP-FPM配置及使用总结

 类似资料: