PHP-FPM 安装和配置文件

实现php-fpm模式
对于php请求,httpd可以用模块和fastcgi两种方式实现动态程序的支持。

fastcgi模式:php处理请求,不再由http服务器自身进行管理,http服务器把http协议转化为factcgi协议,通过socket发送给fastcgi专用进程处理php程序
从稳定性上看,fastcgi是以独立的进程池运行来程序,如果单独一个进程死掉,系统可以很轻易的丢弃,然后重新分配新的进程来运行逻辑。从安全性上看,fastcgi和http的server完全独立, fastcgi怎么down也不会把server搞垮。
从性能上看,fastcgi把动态逻辑的处理从http server中分离出来,大负荷的IO处理还是留给宿主server,这样hpttd server可以一心一意作IO,对于一个普通的动态网页来说,逻辑处理可能只有一小部分,大量的图片等静态IO处理完全不需要逻辑程序的参与。从扩展性上讲,fastcgi是一个中立的技术标准,完全可以支持任何语言写的处理程序,如php,java,python等。而php-fpm就是用来支持php的fastcgi服务器。


httpd+php结合的方式:
module:   php   基于模块,apache换成nginx就不支持。
fastcgi:  php-fpm 基于软件

各种OS版本对fastcgi的支持
CentOS 8: 默认使用fpm模式
	httpd-2.4:默认rpm包支持fcgi模块
	php包默认使用fpm模式
	php-fpm包:专用于将php运行于fpm模式
CentOS 7:
	httpd-2.4:默认rpm包支持fcgi模块
	php-fpm包:专用于将php运行于fpm模式
CentOS 6:
	PHP-5.3.2之前:默认不支持fpm机制;需要自行打补丁并编译安装
	httpd-2.2:默认不支持fcgi协议,需要自行编译此模块
	解决方案:编译安装httpd-2.4, php-5.3.3+




安装 php方法一
yum install php php-fpm

安装 php方法二,指定版本
wget https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm #包含较新的PHP等软件包 
[root@s4 ~]# yum install remi-release-7.rpm
[root@s4 ~]# yum install php56-php-fpm php56-php-mysql -y #安装指定版本的php 
[root@s4 ~]# yum install php72-php-fpm php72-php-mysql -y 

验证安装路径: 
[root@s4 ~]# rpm -ql php72-php-fpm
 /etc/opt/remi/php72/php-fpm.conf 
 /etc/opt/remi/php72/php-fpm.d 
 /etc/opt/remi/php72/php-fpm.d/www.conf 
 /etc/opt/remi/php72/sysconfig/php-fpm 

[root@s4 ~]# cp /opt/remi/php72/root/usr/share/doc/php72-php-common-7.2.24/php.ini- production  /opt/remi/php72/root/usr/etc/php.ini  
[root@s4 ~]# cp /opt/remi/php72/root/usr/share/doc/php72-php-fpm-7.2.24/php- fpm.conf.default   /opt/remi/php72/root/usr/etc/php-fpm.conf


安装 php方法三,编译安装
yum -y install gcc automake autoconf libtool make
yum -y install gcc gcc-c++ glibc
yum -y install libmcrypt-devel mhash-devel libxslt-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel sqlite-devel sqlite

wget https://mirrors.sohu.com/php/php-7.4.16.tar.gz
tar -zxvf php-7.4.16.tar.gz
cd php-7.4.16
./configure --prefix=/usr/local/php  --enable-fpm --with-mcrypt --enable-mbstring --disable-pdo --with-curl --disable-debug  --disable-rpath --enable-inline-optimization --with-bz2  --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --with-mhash --enable-zip --with-pcre-regex --with-mysql --with-mysqli --with-gd --with-jpeg-dir

编译中出现问题:
error: Package requirements (sqlite3 > 3.7.4) were not met
yum install libsqlite3x-devel -y

#oniguruma是一个处理正则表达式的库
error: Package requirements (oniguruma) were not met
yum install oniguruma-devel -y


make && make install


cd /usr/local/php
cp etc/php-fpm.conf.default etc/php-fpm.conf
cd /usr/local/php/etc/php-fpm.d
cp www.conf.default www.conf

/usr/local/php/sbin/php-fpm

  

配置文件

grep "^[a-Z]" /etc/php-fpm.conf 
include=/etc/php-fpm.d/*.conf 
pid = /run/php-fpm/php-fpm.pid 
error_log = /var/log/php-fpm/error.log 
daemonize = yes #是否后台启动


cat /etc/php-fpm.d/www.conf  配置说明
[www]
listen = 127.0.0.1:9000 			#监听地址及IP
listen.allowed_clients = 127.0.0.1  #允许客户端从哪个源IP地址访问,要允许所有行首加 ;注释即可
user = nginx 						#php-fpm启动的用户和组,会涉及到后期文件的权限问题
group = nginx
pm = dynamic 						#动态模式进程管理
pm.max_children = 500 				#静态方式下开启的php-fpm进程数量,在动态方式下他限定php-fpm的最大进程数
pm.start_servers = 100 				#动态模式下初始进程数,必须大于等于pm.min_spare_servers和小于等于pm.max_children的值。
pm.min_spare_servers = 100 			#最小空闲进程数
pm.max_spare_servers = 200 			#最大空闲进程数
pm.max_requests = 500000 			#进程累计请求回收值,会重启
pm.status_path = /pm_status 		#状态访问URL
ping.path = /ping 					#ping访问动地址
ping.response = ping-pong 			#ping返回值
slowlog = /var/log/php-fpm/www-slow.log 					#慢日志路径
php_admin_value[error_log] = /var/log/php-fpm/www-error.log #错误日志
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files 					#phpsession保存方式及路径
php_value[session.save_path] = /var/lib/php/session 		#当时使用file保存session的文件路径




一,php-fpm的启动参数

#测试php-fpm配置
/usr/local/php/sbin/php-fpm -t
/usr/local/php/sbin/php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm.conf -t
 
#启动php-fpm
/usr/local/php/sbin/php-fpm
/usr/local/php/sbin/php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm.conf
 
#关闭php-fpm
kill -INT `cat /usr/local/php/var/run/php-fpm.pid`
 
#重启php-fpm
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

 

二,php-fpm.conf其它重要参数详解

pid = run/php-fpm.pid   			#pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启
error_log = log/php-fpm.log  		#错误日志,默认在安装目录中的var/log/php-fpm.log
log_level = notice 					错误级别. 可用级别为: alert(必须立即处理), error(错误情况), warning(警告情况), notice(一般重要信息), debug(调试信息). 默认: notice.
emergency_restart_threshold = 60
emergency_restart_interval = 60s	#表示在emergency_restart_interval所设值内出现SIGSEGV或者SIGBUS错误的php-cgi进程数如果超过 emergency_restart_threshold个,php-fpm就会优雅重启。这两个选项一般保持默认值。
process_control_timeout = 0			#设置子进程接受主进程复用信号的超时时间. 可用单位: s(秒), m(分), h(小时), 或者 d(天) 默认单位: s(秒). 默认值: 0.
daemonize = yes						#后台执行fpm,默认值为yes,如果为了调试可以改为no。在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置。
listen = 127.0.0.1:9000				#fpm监听端口,即nginx中php处理的地址,一般默认值即可。可用格式为: 'ip:port', 'port', '/path/to/unix/socket'. 每个进程池都需要设置.
listen.backlog = -1 				#backlog数,-1表示无限制,由操作系统决定,此行注释掉就行。backlog含义参考:http://www.3gyou.cc/?p=41
listen.allowed_clients = 127.0.0.1  #允许访问FastCGI进程的IP,设置any为不限制IP,如果要设置其他主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每个地址是用逗号分隔. 如果没有设置或者为空,则允许任何服务器请求连接
listen.owner = www              #unix socket 选项 sock文件所有者
listen.group = www              #unix socket 选项
listen.mode = 0666 			#unix socket设置选项,如果使用tcp方式访问,这里注释即可。
pm = dynamic 				#对于专用服务器,pm可以设置为static。#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定:
pm.max_children #,			#子进程最大数
pm.start_servers 	#, 	#启动时的进程数(pm.min_spare_servers和pm.max_spare_servers之间)
pm.min_spare_servers #,	#保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.max_spare_servers #,	#保证空闲进程数最大值,如果空闲进程大于此值,此进行清理
pm.max_requests = 1000  	#设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.
pm.status_path = /status	#FPM状态页面的网址. 如果没有设置, 则无法访问状态页面. 默认值: none. munin监控会使用到
ping.path = /ping			#FPM监控页面的ping网址. 如果没有设置, 则无法访问ping页面. 该页面用于外部检测FPM是否存活并且可以响应请求. 请注意必须以斜线开头 (/)。
ping.response = pong		#用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.
request_terminate_timeout = 0	#设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的'max_execution_time'因为某些特殊原因没有中止运行的脚本有用. 设置为 '0' 表示 'Off'.当经常出现502错误时可以尝试更改此选项。
request_slowlog_timeout = 10s	#当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 '0' 表示 'Off'
slowlog = log/$pool.log.slow	#慢请求的记录日志,配合request_slowlog_timeout使用
rlimit_files = 1024				#设置文件打开描述符的rlimit限制. 默认值: 系统定义值默认可打开句柄是1024,可使用 ulimit -n查看,ulimit -n 2048修改。
rlimit_core = 0					#设置核心rlimit最大限制值. 可用值: 'unlimited' 、0或者正整数. 默认值: 系统定义值.
chroot =						#启动时的Chroot目录. 所定义的目录需要是绝对路径. 如果没有设置, 则chroot不被使用.
chdir =							#设置启动目录,启动时会自动Chdir到该目录. 所定义的目录需要是绝对路径. 默认值: 当前目录,或者/目录(chroot时)
catch_workers_output = yes		#重定向运行过程中的stdout和stderr到主要的错误日志文件中. 如果没有设置, stdout 和 stderr 将会根据FastCGI的规则被重定向到 /dev/null . 默认值: 空.



状态页
pool             		– fpm池子名称,大多数为www
process manager    	 	– 进程管理方式,值:static, dynamic or ondemand. dynamic
start time         		– 启动日期,如果reload了php-fpm,时间会更新
start since         	– 运行时长
accepted conn          	– 当前池子接受的请求数
listen queue         	– 请求等待队列,如果这个值不为0,那么要增加FPM的进程数量
max listen queue     	– 请求等待队列最高的数量
listen queue len     	– socket等待队列长度
idle processes          – 空闲进程数量
active processes        – 活跃进程数量
total processes         – 总进程数量
max active processes    – 最大的活跃进程数量(FPM启动开始算)
max children reached    - 进程最大数量限制的次数,如果这个数量不为0,那说明你的最大进程数量太小了,请改大一点。
slow requests           – 启用了php-fpm slow-log,缓慢请求的数量






三、常见错误及解决办法整理
1,request_terminate_timeout引起的资源问题
request_terminate_timeout的值如果设置为0或者过长的时间,可能会引起file_get_contents的资源问题。
如果file_get_contents请求的远程资源如果反应过慢,file_get_contents就会一直卡在那里不会超时。我们知道php.ini 里面max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的request_terminate_timeout参数。
request_terminate_timeout默认值为 0 秒,也就是说,PHP 脚本会一直执行下去。这样,当所有的 php-cgi 进程都卡在 file_get_contents() 函数时,这台 Nginx+PHP 的 WebServer 已经无法再处理新的 PHP 请求了,Nginx 将给用户返回“502 Bad Gateway”。修改该参数,设置一个 PHP 脚本最大执行时间是必要的,但是,治标不治本。例如改成 30s,如果发生 file_get_contents() 获取网页内容较慢的情况,这就意味着 150 个 php-cgi 进程,每秒钟只能处理 5 个请求,WebServer 同样很难避免”502 Bad Gateway”。解决办法是request_terminate_timeout设置为10s或者一个合理的值,或者给file_get_contents加一个超时参数。


2,max_requests参数配置不当,可能会引起间歇性502错误:
pm.max_requests = 1000
设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 ’0′ 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.
这段配置的意思是,当一个 PHP-CGI 进程处理的请求数累积到 500 个后,自动重启该进程。

但是为什么要重启进程呢?
一般在项目中,我们多多少少都会用到一些 PHP 的第三方库,这些第三方库经常存在内存泄漏问题,如果不定期重启 PHP-CGI 进程,势必造成内存使用量不断增长。因此 PHP-FPM 作为 PHP-CGI 的管理器,提供了这么一项监控功能,对请求达到指定次数的 PHP-CGI 进程进行重启,保证内存使用量不增长。
正是因为这个机制,在高并发的站点中,经常导致 502 错误,我猜测原因是 PHP-FPM 对从 NGINX 过来的请求队列没处理好。不过我目前用的还是 PHP 5.3.2,不知道在 PHP 5.3.3 中是否还存在这个问题。
目前我们的解决方法是,把这个值尽量设置大些,尽可能减少 PHP-CGI 重新 SPAWN 的次数,同时也能提高总体性能。在我们自己实际的生产环境中发现,内存泄漏并不明显,因此我们将这个值设置得非常大(204800)。大家要根据自己的实际情况设置这个值,不能盲目地加大。
话说回来,这套机制目的只为保证 PHP-CGI 不过分地占用内存,为何不通过检测内存的方式来处理呢?我非常认同高春辉所说的,通过设置进程的峰值内在占用量来重启 PHP-CGI 进程,会是更好的一个解决方案。

3,php-fpm的慢日志,debug及异常排查神器:
request_slowlog_timeout设置一个超时的参数,slowlog设置慢日志的存放位置
tail -f /var/log/www.slow.log
 

  

 

posted @ 2022-08-22 10:34  yuanbangchen  阅读(497)  评论(0编辑  收藏  举报