php-fpm工作流程
php-fpm全名是PHP FastCGI进程管理器
php-fpm启动后会先读php.ini,然后再读相应的conf配置文件,conf配置可以覆盖php.ini的配置。
启动php-fpm之后,会创建一个master进程,监听9000端口(可配置),master进程又会根据fpm.conf/www.conf去创建若干子进程,子进程用于处理实际的业务。
当有客户端(比如nginx)来连接9000端口时,空闲子进程会自己去accept,如果子进程全部处于忙碌状态,新进的待accept的连接会被master放进队列里,等待fpm子进程空闲;
这个存放待accept的半连接的队列有多长,由 listen.backlog 配置。
php-fpm全局配置说明
配置里面的所有相对路径,都是相对于php的安装路径。
除了有php-fpm.conf配置文件外,通常还有其他的*.conf配置文件(也可以不要,直接在php-fpm.conf配置)用于配置进程池,不同的进程池可以用不同的用户执行,监听不同的端口,处理不同的任务;多个进程池共用一个全局配置。
include=/opt/remi/php56/root/etc/php-fpm.d/*.conf 载入其他的配置文件。
php-fpm全局配置参数中文说明:
pid = /opt/remi/php56/root/var/run/php-fpm/php-fpm.pid
#pid进程文件,默认为none。
error_log = /opt/remi/php56/root/var/log/php-fpm/error.log
#错误日志位置,默认:安装路径 #INSTALL_PREFIX#/log/php-fpm.log。如果设置为syslog,log就会发送给syslogd服务而不会写进文件里。
syslog.facility = daemon
#把日志写进系统log,linux还不够熟悉,暂时不用理会。
syslog.ident = php-fpm
#系统日志标示,如果跑了多个fpm进程,需要用这个来区分日志是谁的。
log_level = notice
#日志等级,默认notice,可选:alert, error, warning, notice, debug
emergency_restart_threshold = 60
#配合下面emergency_restart_interval参数
emergency_restart_interval = 60s
#如果在此参数设置的时间内,出现SIGSEGV或SIGBUS的子进程数超过emergency_restart_threshold参数设置的值,那么fpm就会优雅的重启,值是0表示off这个功能,可用的单位有:s秒,m分,h时,d天。
process_control_timeout = 0
#设置子进程接受主进程复用信号的超时时间。这个每天明白,是过了这个时间就不能复用了?
process.max = 128
#当动态管理子进程时,fpm最多能fork多少个进程,0表示无限制,这是所有进程池能启动子进程的总和,谨慎使用。
process.priority = -19
#设置子进程的优先级,在master进程以root用户启动时有效;如果没有设置,子进程会继承master进程的优先级,值范围-19(最高)到20(最低),默认不设置。
daemonize = yes
#设置成no用于调试bug,默认为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 = 10s
#当fpm被设置为系统服务时,多久向服务器报告一次状态,单位有s,m,h。
php-fpm进程池配置 pool Definitions:
在不同的监听端口和不同的管理选项下可以跑任意数量的池,并没有个数限制;
池的名字用于 logs 和 stats。
user = apache
group = apache
#以什么用户什么组的权限来运行池fpm。
用apache可以像httpd服务一样去访问某些目录
listen = 127.0.0.1:9000
#监听的ip和端口,可以 /path/to/unix/socket 来监听unix socket,性能更好。
listen.backlog = 65535
#未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。
listen.owner = apache
listen.group = apache
listen.mode = 0660
#用socket连接方式时,指定拥有unix socket权限的用户,默认和运行的用户一样;用tcp连接可以注释掉
listen.allowed_clients = 127.0.0.1
#设置允许连接fpm的地址,比如nginx就要来连,多个地址用逗号隔开,如果不配置,则默认任意地址都能来连。
process.priority = -19
#池进程的权限,同样要master进程是root用户才有效,和全局那个一样,不设置的话会继承master进程的优先级。
pm = dynamic
#启动时子进程管理方式,可选值:static(启动时创建指定个数), dynamic(启动时根据情况创建,至少有一个), ondemand(启动时不创建子进程,有需求才创建)
pm.max_children = 5
#该池同时最多存在5个进程, 三种管理方式都要配置
pm.start_servers = 2
#fpm启动时创建2个子进程,只适用动态dynamic管理方式
pm.min_spare_servers = 2
#服务器闲置时最少保持2个子进程,不够这个数就会创建,只适用动态dynamic管理方式
pm.max_spare_servers = 3
#服务器闲置时最多要有几个,多了会kill,只适用动态dynamic管理方式
pm.process_idle_timeout = 10s
#子进程闲置10s后就会被杀掉。
pm.max_requests = 500
#每个子进程最大处理500请求就被回收,可防止内存泄露。
pm.status_path string
#FPM 状态页面的网址。如果没有设置,则无法访问状态页面,默认值:无。
ping.path string
#FPM 监控页面的 ping 网址。如果没有设置,则无法访问 ping 页面。该页面用于外部检测 FPM 是否存活并且可以响应请求。请注意必须以斜线开头(/)。
ping.response string
#用于定义 ping 请求的返回响应。返回为 HTTP 200 的 text/plain 格式文本。默认值:pong。
process.priority int
#设置 worker 的 nice(2)优先级(如果设置了的话)。 该值从 -19(最高优先级) 到 20(更低优先级)。 默认值:不设置
prefix string
#检测路径时使用的前缀
access.log = var/log/$pool.access.log
#访问文件日志,没啥用处,比如yii2每次都记录访问index.php,只是记录真实的PHP文件。
slowlog = var/log/$pool.log.slow
#PHP文件执行过慢的日志,会准确的记录具体哪一行代码太慢,这个非常有用,在设置了时间时生效。
request_slowlog_timeout = 2s
#超过这个运行时间就会写慢日志
request_terminate_timeout = 3s
#单个请求的超时时间,有时候php.ini设置的最大执行时间未生效,这个就会来干掉那个执行太久的请求。
rlimit_files = 1024
#最大打开句柄数,默认为系统值。
rlimit_core = 0
#最多的核心使用数,默认为系统分配。
chroot = /path
#路径必须是绝对路径,改变子进程的跟目录,可以把进程对文件系统的读写与实际的操作系统文件系统隔离,对安全有好处。
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
#为了安全,限制能执行的脚本后缀
#为当前池指定另外的 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。
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
#这种方法设置 `disable_functions` 和 `disable_classes` 时,不会覆盖 php.ini 的设置,只会追加。
注意:PHP配置值通过 php_value 或者 php_flag 设置,并且会覆盖以前的值。
disable_functions 或者 disable_classes 在 php.ini 之中定义的值不会被覆盖掉,但是会将新的设置附加在原有值的后面。
使用 php_admin_value 或者 php_admin_flag 定义的值,不能被 PHP 代码中的 ini_set() 覆盖。
自 5.3.3 起,也可以通过 web 服务器设置 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 有权限访问。
总结:
sock文件随便创建到哪里都可以,只要fpm有权限在那个目录里写文件,nginx有权限去读就可以。tcp连接会更稳定,因为有tcp协议保证数据的正确性,但是sock有更少的数据拷贝和上下文切换,更少的资源占用。不过只能在nginx和fpm在同一台机器上才能用sock。
php-fpm进程状态监控
1、nginx配置:遇到 status 的请求,直接转发给php
location ~^/status$ {
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
2、fpm配置:pm.status_path = /status
3、然后重新fpm和nginx,在浏览器里访问就能看到了:
默认以 text/plain 展示结果,可以传参数 ?json/html/xml 分别得到json等格式的结果;参数full可以查看每个子进程的明细
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参数。
大部分参数只要系统默认的就可以了,我们只需要知道几个比较重要的参数设置,什么时候用到可以回头查询相关说明
##################################################################################################################################################################################################################
第一部分:FPM 配置
参数 | 说明
-p | 命令行中动态修改–prefix
;include=etc/fpm.d/*.conf | 用于包含一个或多个文件,如果glob(3)存在(glob()函数返回匹配指定模式的文件名或目录)
第二部分:全局配置
由标志[global]开始:
;pid = run/php-fpm.pid 设置pid文件的位置,默认目录路径 /usr/local/php/var
;error_log = log/php-fpm.log 记录错误日志的文件,默认目录路径 /usr/local/php/var
;syslog.facility = daemon 用于指定什么类型的程序日志消息。
;syslog.ident = php-fpm 用于FPM多实例甄别
;log_level = notice 记录日志的等级,默认notice,可取值alert, error, warning, notice, debug
;emergency_restart_threshold = 0 如果子进程在这个时间段内带有IGSEGV或SIGBUS退出,则重启fpm,默认0表示关闭这个功能
;emergency_restart_interval = 0 设置时间间隔来决定服务的初始化时间(默认单位:s秒),可选s秒,m分,h时,d天
;process_control_timeout = 0 子进程等待master进程对信号的回应(默认单位:s秒),可选s秒,m分,h时,d天
; process.max = 128 控制最大进程数,使用时需谨慎
; process.priority = -19 处理nice(2)的进程优先级别-19(最高)到20(最低)
;rlimit_files = 1024 设置主进程文件描述符rlimit的数量
;rlimit_core = 0 设置主进程rlimit最大核数
;events.mechanism = epoll 使用处理event事件的机制
; - 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)
;daemonize = yes 将fpm转至后台运行,如果设置为“no”,那么fpm会运行在前台
;systemd_interval = 10
第三部分:进程池的定义
通过监听不同的端口和不用管理选择可以定义多个不同的子进程池,进程池被用与记录和统计,对于fpm能够处理进程池数目的多少并没有限制
其中$pool变量可以在任何指令中使用,他将会替代相应的进程池名字。例如:这里的[www]
[root@test ~]# ps -ef | grep php-fpm
root 3028 1 0 20:33 ? 00:00:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
nobody 3029 3028 0 20:33 ? 00:00:00 php-fpm: pool www
nobody 3030 3028 0 20:33 ? 00:00:00 php-fpm: pool www
[www]
; It only applies on the following directives:
; - 'access.log'
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
;prefix = /path/to/pools/$pool 如果没有制定,将使用全局prefix替代
user = nobody 进程的发起用户和用户组,用户user是必须设置,group不是
group = nobody
listen = 127.0.0.1:9000 监听ip和端口
;listen.backlog = 65535 设置listen(2)函数backlog
;listen.owner = nobody
;listen.group = nobody
;listen.mode = 0660
;listen.acl_users =
;listen.acl_groups =
;listen.allowed_clients = 127.0.0.1 允许FastCGI客户端连接的IPv4地址,多个地址用','分隔,为空则允许任何地址发来链接请求
; process.priority = -19
pm = dynamic 选择进程池管理器如何控制子进程的数量
static: 对于子进程的开启数路给定一个锁定的值(pm.max_children)
dynamic: 子进程的数目为动态的,它的数目基于下面的指令的值(以下为dynamic适用参数)
pm.max_children: 同一时刻能够存货的最大子进程的数量
pm.start_servers: 在启动时启动的子进程数量
pm.min_spare_servers: 处于空闲"idle"状态的最小子进程,如果空闲进程数量小于这个值,那么相应的子进程会被创建
pm.max_spare_servers: 最大空闲子进程数量,空闲子进程数量超过这个值,那么相应的子进程会被杀掉。
ondemand: 在启动时不会创建,只有当发起请求链接时才会创建(pm.max_children, pm.process_idle_timeout)
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
;pm.process_idle_timeout = 10s; 空闲进程超时时间
;pm.max_requests = 500 在派生新的子进程前,每一个子进程应该处理的请求数目,在第三方库中解决内存溢出很有用,设置为0则不会限制
;pm.status_path = /status 配置一个URI,以便查看fpm状态页
状态页描述:
accepted conn: 该进程池接受的请求数量
pool: 进程池的名字
process manager: 进程管理,就是配置中pm指令,可以选择值static,dynamic,ondemand
idle processes: 空闲进程数量
active processes: 当前活跃的进程数量
total processes: 总的进程数量=idle+active
max children reached: 达到最大子进程的次数,达到进程的限制,当pm试图开启更多的子进程的时候(仅当pm工作在dynamic时)
;ping.path = /ping 该ping URI将会去调用fpm监控页面,如果这个没有设置,那么不会有URI被做为ping页
;ping.response = pong 用于定制平请求的响应,响应的格式text/plain(对200响应代码)
;access.log = log/$pool.access.log
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
; The following syntax is allowed
; %%: the '%' character
; %C: %CPU used by the request
; it can accept the following format:
; - %{user}C for user CPU only
; - %{system}C for system CPU only
; - %{total}C for user + system CPU (default)
; %d: time taken to serve the request
; it can accept the following format:
; - %{seconds}d (default)
; - %{miliseconds}d
; - %{mili}d
; - %{microseconds}d
; - %{micro}d
; %e: an environment variable (same as $_ENV or $_SERVER)
; it must be associated with embraces to specify the name of the env
; variable. Some exemples:
; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
; %f: script filename
; %l: content-length of the request (for POST request only)
; %m: request method
; %M: peak of memory allocated by PHP
; it can accept the following format:
; - %{bytes}M (default)
; - %{kilobytes}M
; - %{kilo}M
; - %{megabytes}M
; - %{mega}M
; %n: pool name
; %o: output header
; it must be associated with embraces to specify the name of the header:
; - %{Content-Type}o
; - %{X-Powered-By}o
; - %{Transfert-Encoding}o
; - ....
; %p: PID of the child that serviced the request
; %P: PID of the parent of the child that serviced the request
; %q: the query string
; %Q: the '?' character if query string exists
; %r: the request URI (without the query string, see %q and %Q)
; %R: remote IP address
; %s: status (response code)
; %t: server time the request was received
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %T: time the log has been written (the request has finished)
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %u: remote user
;slowlog = log/$pool.log.slow 用于记录慢请求
;request_slowlog_timeout = 0 慢日志请求超时时间,对一个php程序进行跟踪。
;request_terminate_timeout = 0 终止请求超时时间,在worker进程被杀掉之后,提供单个请求的超时间隔。由于某种原因不停止脚本执行时,应该使用该选项,0表示关闭不启用
(在php.ini中,max_execution_time 一般设置为30,表示每一个脚本的最大执行时间)
;rlimit_files = 1024 设置打开文件描述符的限制
;rlimit_core = 0 设置内核对资源的使用限制,用于内核转储
;chroot = 设置chroot路径,程序一启动就将其chroot放置到指定的目录下,该指令值必须是一个绝对路径
;chdir = /var/www 在程序启动时将会改变到指定的位置(这个是相对路径,相对当前路径或chroot后的“/”目录)
;catch_workers_output = yes 将worker的标准输出和错误输出重定向到主要的错误日志记录中,如果没有设置,根据FastCGI的指定,将会被重定向到/dev/null上
;clear_env = no 清理环境
;security.limit_extensions = .php .php3 .php4 .php5 限制FPM执行解析的扩展名
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp
; Additional php.ini defines, specific to this pool of workers. These settings
; overwrite the values previously defined in the php.ini. The directives are the
; same as the PHP SAPI:
; php_value/php_flag - you can set classic ini defines which can
; be overwritten from PHP call 'ini_set'.
; php_admin_value/php_admin_flag - these directives won't be overwritten by
; PHP call 'ini_set'
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
; Defining 'extension' will load the corresponding shared extension from
; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
; overwrite previously defined php.ini values, but will append the new value
; instead.
;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-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足够健康,这个需要根据实际情况加以限定。