nginx+php-fpm出现502 bad gateway错误解决方法

4,238次阅读
一条评论

共计 6374 个字符,预计需要花费 16 分钟才能阅读完成。

502 错误是所有用 nginx 跑 php 的运维人员不愿意看见的

nginx 出现 502 有很多原因,但大部分原因可以归结为资源数量不够用, 也就是说后端 php-fpm 处理有问题,nginx 将正确的客户端请求发给了后端的 php-fpm 进程,但是因为 php-fpm 进程的问题导致不能正确解析 php 代码,最终返回给了客户端 502 错误。

服务器出现 502 的原因是连接超时 我们向服务器发送请求 由于服务器当前链接太多,导致服务器方面无法给于正常的响应, 产生此类报错

因此如果你服务器并发量非常大,那只能先增加机器,然后按以下方式优化会取得更好效果; 但如果你并发不大却出现 502,一般都可以归结为配置问题,脚本超时问题。

1.php-fpm 进程数不够用

使用 netstat -napo |grep “php-fpm” | wc -l 查看一下当前 fastcgi 进程个数,如果个数接近 conf 里配置的上限,就需要调高进程数。

但也不能无休止调高,可以根据服务器内存情况,可以把 php-fpm 子进程数调到 100 或以上,在 4G 内存的服务器上 200 就可以。

2. 调高调高 linux 内核打开文件数量

可以使用这些命令 (必须是 root 帐号)

echo ‘ulimit -HSn 65536’ >> /etc/profile

echo ‘ulimit -HSn 65536’ >> /etc/rc.local

source /etc/profile

 3. 脚本执行时间超时

如果脚本因为某种原因长时间等待不返回,导致新来的请求不能得到处理,可以适当调小如下配置。

nginx.conf 里面主要是如下

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

php-fpm.conf 里如要是如下

request_terminate_timeout = 10s

4. 缓存设置比较小

修改或增加配置到 nginx.conf

proxy_buffer_size 64k;
proxy_buffers  512k;
proxy_busy_buffers_size 128k;

5. recv() failed (104: Connection reset by peer) while reading response header from upstream

可能的原因机房网络丢包或者机房有硬件防火墙禁止访问该域名

但最重要的是程序里要设置好超时,不要使用 php-fpm 的 request_terminate_timeout,

最好设成 request_terminate_timeout=0;

因为这个参数会直接杀掉 php 进程,然后重启 php 进程,这样前端 nginx 就会返回 104: Connection reset by peer。这个过程是很慢,总体感觉就是网站很卡。

May 01 10:50:58.044162 [WARNING] [pool www] child 4074, script ‘/usr/local/nginx/html/quancha/sameip/detail.php’ execution timed out (15.129933 sec), terminating
May 01 10:50:58.045725 [WARNING] [pool www] child 4074 exited on signal 15 SIGTERM after 90.227060 seconds from start
May 01 10:50:58.046818 [NOTICE] [pool www] child 4082 started

说一千道一万最重要的就是程序里控制好超时,gethostbyname、curl、file_get_contents 等函数的都要设置超时时间。

另一个就是多说,这个东西是增加了网站的交互性,但是使用的多了反应就慢了,如果你网站超时且使用了多说是,可以关闭它。

近日,服务器出现异常,网站不能正常访问。经排查是 php 的问题。

在重启 php-fpm 时,恢复正常。1 分钟之后又出现故障。查看 php 日志文件 /usr/local/php/var/log 后提示

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

子进程数已经达到设置的最大值。

要设置 php 进程数量。需要在 php-fpm.conf 文件中修改。

先看 /usr/local/php/etc/php-fpm.conf 文件各项配置解析

nginx+php-fpm 出现 502 bad gateway 错误解决方法
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
listen.group = www
listen.mode = 0666
#unix socket 设置选项,如果使用 tcp 方式访问,这里注释即可。user = www
group = www
#启动进程的帐户和组
 
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.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 . 默认值: 空.

 

根据以上配置的解析,在 php-fpm.conf 文件中添加如下配置:

pm.max_children = 100

pm.start_servers = 30

pm.min_spare_servers = 20

pm.max_spare_servers = 100

pm.max_requests = 500

 

以观后效。

 

另附豆瓣技术贴:https://www.douban.com/note/315222037/

 

1、php-fpm 优化参数介绍
他们分别是:pm、pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers。

pm:表示使用那种方式,有两个值可以选择,就是 static(静态)或者 dynamic(动态)。
在更老一些的版本中,dynamic 被称作 apache-like。这个要注意看配置文件的说明。

下面 4 个参数的意思分别为:

pm.max_children:静态方式下开启的 php-fpm 进程数量
pm.start_servers:动态方式下的起始 php-fpm 进程数量
pm.min_spare_servers:动态方式下的最小 php-fpm 进程数
pm.max_spare_servers:动态方式下的最大 php-fpm 进程数量

区别:

如果 dm 设置为 static,那么其实只有 pm.max_children 这个参数生效。系统会开启设置数量的 php-fpm 进程。
如果 dm 设置为 dynamic,那么 pm.max_children 参数失效,后面 3 个参数生效。
系统会在 php-fpm 运行开始 的时候启动 pm.start_servers 个 php-fpm 进程,
然后根据系统的需求动态在 pm.min_spare_servers 和 pm.max_spare_servers 之间调整 php-fpm 进程数

2、服务器具体配置
对于我们的服务器,选择哪种执行方式比较好呢?事实上,跟 Apache 一样,运行的 PHP 程序在执行完成后,或多或少会有内存泄露的问题。
这也是为什么开始的时候一个 php-fpm 进程只占用 3M 左右内存,运行一段时间后就会上升到 20-30M 的原因了。
对于内存大的服务器(比如 8G 以上)来说,指定静态的 max_children 实际上更为妥当,因为这样不需要进行额外的进程数目控制,会提高效率。
因为频繁开关 php-fpm 进程也会有时滞,所以内存够大的情况下开静态效果会更好。数量也可以根据 内存 /30M 得到,比如 8GB 内存可以设置为 100,
那么 php-fpm 耗费的内存就能控制在 2G-3G 的样子。如果内存稍微小点,比如 1G,那么指定静态的进程数量更加有利于服务器的稳定。
这样可以保证 php-fpm 只获取够用的内存,将不多的内存分配给其他应用去使用,会使系统的运行更加畅通。
对于小内存的服务器来说,比如 256M 内存的 VPS,即使按照一个 20M 的内存量来算,10 个 php-cgi 进程就将耗掉 200M 内存,那系统的崩溃就应该很正常了。
因此应该尽量地控制 php-fpm 进程的数量,大体明确其他应用占用的内存后,给它指定一个静态的小数量,会让系统更加平稳一些。或者使用动态方式,
因为动态方式会结束掉多余的进程,可以回收释放一些内存,所以推荐在内存较少的服务器或 VPS 上使用。具体最大数量根据 内存 /20M 得到。
比如说 512M 的 VPS,建议 pm.max_spare_servers 设置为 20。至于 pm.min_spare_servers,则建议根据服务器的负载情况来设置,比如服务器上只是部署 php 环境的话,比较合适的值在 5~10 之间。

本服务器配置

1、服务器基本信息:
硬盘:数据盘 30G、系统盘 20G
内存:1.5G
CPU:双核
系统:CentOS 6.3 64 位
带宽:独享 2M
2、部署的应用
Git、SVN、Apache、Tomcat、PHP、Nginx、Mysql、JDK
3、优化后的参数
pm = dynamic
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 8

 

pm.max_requests = 500

设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为’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)。大家要根据自己的实际情况设置这个值,不能盲目地加大。

正文完
 0
评论(一条评论)
hjurtgq
2019-05-20 00:37:29 回复

Спасибо за информацию!!!!!

 Windows  Opera  巴西Claro