为什么PHP项目运行报错502,Nginx + php-fpm 出现502错误分析
在nginx上跑php容易出现502错误,很多人遇到过这个问题,到底是什么原因导致的呢?
出现502错误后,又有哪些解决办法呢?
本文源起于前段时间处理无线浏览器的一次502报警后总结得来,希望能为大家提供参考。
从报警说起
现象
1、打开静态页面很快,如无线浏览器的更新日志页面,请求云控接口却很慢,报502错误。
2、最开始一周报警1-2次,后来发展到一天报警1次。
处理过程
1、查看错误日志,发现502错误的响应时间都比较长,均为21s左右。见下图:
日志中请求的是云控接口,就是一个读取配置文件然后吐出数据的过程,正常情况下响应时间应该是非常短的。
因此直观猜测是php进程堵死了,云控请求过来时php进程不够用了,从而导致502错误。
使用 netstat -napo | grep "php-fpm" | wc -l 查看了一下当前fastcgi进程个数, 发现已达到php-fpm.conf中pm.max_children的设置值。
重启php-fpm后,报警得以解除,但这并没有找到问题根源,php进程为什么会堵死呢?
2、猜测进程堵死的原因应该是大量的慢请求导致的。在/usr/local/php/etc/php-fpm.conf文件中,发现有关于慢日志的设置:
slowlog = /data/php/log/$pool.log.slow
request_slowlog_timeout = 10
request_terminate_timeout = 0
request_terminate_timeout配置的是一个php脚本的最大执行时间,默认是0s。
0s的含义是让php脚本一直执行下去而没有时间限制。
当再次收到报警时,查看php的slow log,果然发现发现大量执行时间超过10s的脚本。慢日志如下:
11-Aug-2014 08:34:53 pool www pid 8683
script_filename = /home/q/system/api.mse.360.cn/src/www/api//index.php0x00000000013d0420 curl_exec() /home/q/system/api.mse.360.cn/src/application/models/bizservice/icon_svc.php:291
0x00000000013cff98 httpRequest() /home/q/system/api.mse.360.cn/src/application/models/bizservice/icon_svc.php:203
0x00000000013cf710 getTitleBySite() /home/q/system/api.mse.360.cn/src/application/models/bizservice/icon_svc.php:33
0x00000000013cf260 getIconAndTitleBySite() /home/q/system/api.mse.360.cn/src/application/controllers/api/IconController.php:25
0x00000000013cf0c0 addSiteAction() /home/q/php/QFrameSmarty/web/QFrameaction.php:46
0x00000000013ce9a0 dispatch() /home/q/php/QFrameSmarty/web/QFrameweb.php:176
0x00000000013ce4b0 dispatch() /home/q/php/QFrameSmarty/web/QFrameweb.php:150
0x00000000013ce190 runController() /home/q/php/QFrameSmarty/web/QFrameweb.php:129
0x00000000013ce018 processRequest() /home/q/php/QFrameSmarty/web/QFrameweb.php:37
0x00000000013cdc50 run() /home/q/system/api.mse.360.cn/src/www/api/index.php:15
终于找到php进程堵死的根源:调用添加icon到浏览器主屏这个接口时,大量的curl抓取页面title执行超时。
慢请求过多导致php进程不能及时释放,所以触发报警。
添加curl的执行超时,上线代码后,php进程终于治“堵”成功,nginx+php-fpm的502报警彻底解除。
为什么会出现502
一般而言,nginx出现502有很多原因,但大都可以归结为资源数量不够用,也就是说后端php-fpm处理有问题。
nginx将正确的客户端请求发给后端的php-fpm进程,由于php-fpm进程的问题导致不能正确解析php代码,最终返回502错误。
1、php-fpm进程数不够用
nginx和fastcgi是通过socket进行连接的,一个php-fpm进程在同一时刻只能响应一个用户请求。它能处理的最大请求数由php-fpm.conf中如下配置决定:
listen.backlog = 128
pm.max_children = 256
这是我们线上服务器的配置,也就是说php-fpm能处理的最大请求数为384。
当客户端的请求数超过这个值时,再试图发送请求会收到Resource temporarily unavailable,这时nginx就会报502错误。
上面提到的业务报警就是由于php-fpm进程数不够用而导致的。
大量慢请求占据了php进程,php-fpm进程数很快达到峰值。php-fpm被卡死不能处理新的请求时,nginx并不会收到请求被拒绝的类似信息,而是把请求积压在socket上;
此时浏览器所得到的响应就是一个“正在等待响应”的提示,除非socket报错或浏览器关闭否则等待永远不会停止。
当积压数超过backlog的设置值时,高峰时间大量的云控请求就会触发服务端的502报警。
为了验证这一结论,在测试服务器上修改php-fpm.conf文件中的配置进行一个简单测试。
修改php-fpm.conf的相关配置如下:
listen.backlog = 8
pm = dynamic pm.max_children = 8
pm.min_spare_servers = 2
pm.max_spare_servers = 4
重启php-fpm,客户端发送多于16个请求,每个请求脚本都sleep 10s。采用http_load进行压测,结果如下:
21 fetches, 25 max parallel, 18044 bytes, in 30.0058 seconds
859.238 mean bytes/connection
0.699864 fetches/sec, 601.35 bytes/sec
msecs/connect: 0.472571 mean, 0.637 max, 0.229 min
msecs/first-response: 17094.7 mean, 22743.7 max, 10002.3 min
5 bad byte counts
HTTP response codes:
code 200 – 16
code 502 – 5
从压测结果可以看到,php-fpm能处理的最大请求数应为16,超出这个值的请求会报502错误。
2、php脚本执行超时
在php.ini和php-fpm.conf中分别有这样两个配置项:max_execution_time和request_terminate_timeout。
文档中对其注释如下:;
The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' ini option
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
;request_terminate_timeout = 0
这两项都是用来配置一个php脚本的最大执行时间的,默认为0s。
当超过这个时间时,php-fpm不仅会终止脚本的执行,还会终止执行脚本的worker进程。
当Nginx会发现与自己通信的socket连接断掉了,以为上游服务器挂了,于是返回给客户端502错误。
修改php-fpm.conf配置如下:
request_terminate_timeout = 10
重启php-fpm,写一个php脚本,sleep 20s。打开浏览器访问测试页面,执行该php脚本验证一下,结果如下图:
由于php脚本执行时间超过配置规定时间,进程被异常终止,所以nginx返回502,验证了上面的结论。
如何避免502
如果服务器并发量非常大,那只能先增加机器,然后按以下方式优化会取得更好效果;但如果并发不大却出现502,一般都可以归结为上述两个原因,php-fpm进程数不够用和php脚本执行超时。
1、增加php-fpm进程数
使用 netstat -napo | grep "php-fpm" | wc -l 查看一下当前fastcgi进程个数。
如果个数接近 php-fpm.conf里配置的pm.max_children上限,就需要调高进程数。
因为max_children设置的较小,那么fastcgi就会“很累”,处理速度也很慢,等待的时间也较长。
但设置max_children也会受到机器资源的限制,因此也并不能无限增加,增大进程数,内存占用也会相应增大。
正常情况下每个php-fpm进程所耗费的内存在20M左右,因此我们线上服务器的配置基本上是最佳的。
2、调整request_terminate_timeout
request_terminate_timeout可以根据服务器的性能进行设定,一般来说性能越好你可以设置越高。
在我们的线上服务器建议直接使用默认值0s就可以了,这样能够避免php进程被异常终止而导致502错误。
可以看到,增加php-fpm进程数和调整request_terminate_timeout均属于配置问题。
在我们的线上环境,相关配置基本上已达到最优,此时要避免502最最重要的还是要控制好程序中的超时。
curl、file_get_contents等函数都要设置超时时间,mysql慢查询请求也要尽量避免。
总结一下
1、nginx出现502错误一般都是后端的php-fpm出问题引起的。
2、pm.max_children不能无限增加,要视机器资源而定。
3、php-fpm.conf中request_terminate_timeout最好采用默认值。
4、大量的慢请求往往才是502的罪魁祸首,所以请一定要管好你程序中的超时。
为什么PHP项目运行报错502,Nginx + php-fpm 出现502错误分析相关推荐
- vue/cle3项目运行报错sockjs-node/info解决方案
https://cloud.tencent.com/developer/article/1489598 vue/cle3项目运行报错sockjs-node/info解决方案 在这篇文章中: bug复现 ...
- 【项目运行报错】These dependencies were not found: core-js/modules/es6.array.fill in ./node_modules
项目运行报错 These dependencies were not found: core-js/modules/es6.array.fill in ./node_modules/cache-loa ...
- vue 项目运行报错 multiple chunks emit assts to the same filename js/401.js(chunks 401 and 401)
VUE项目运行报这个错误也没有说哪里有错误,只说有名字冲突,整个项目搜下来都没发现有相同的名字,百度也没人说.自己摸索的解决掉了.有两种情况. 情况一:如果是添加路由的时候就报这个错 解决办法: 把c ...
- 为什么PHP项目运行报错502,Nginx+PHP-FPM遇到的502报错
1 首先查看一下目前php-fpm的进程数量 ps aux |grep php-fpm |grep -v grep |grep "^www"|wc -l 将输出结果与nginx.c ...
- 为什么PHP项目运行报错502,PHP的502报错
相信自己,加油! **** nginx+php 出现502 bad gateway,一般这都不是nginx的问题,而是由于 fastcgi或者php的问题导致的 服务器出现 502 的原因是连接超时 ...
- vue项目运行报错 node_modules/.bin/vue-cli-service: Permission denied
vue项目运行 npm run serve 报错 sh: /Users/wang/WebstormProjects/test_web/node_modules/.bin/vue-cli-service ...
- Python项目运行报错 django.core.exceptions.ImproperlyConfigured: WSGI application ‘WebTool.wsgi.application
问题描述:使用Pycharm运行python项目报错:django.core.exceptions.ImproperlyConfigured: WSGI application 'WebTool.ws ...
- 查看node的位置_升级Node版本RN项目运行报错cb.apply is not a function
今日打算安装一下ReactNative官方推荐的脚手架工具Ignite. infinitered/ignitegithub.com Ignite是一套整合了 Redux 以及一些常见 UI 组件的脚 ...
- vue使用vuetify创建项目运行报错:error Component name XXX should always be multi-word vue/multi-word-compon
报错如下: You may use special comments to disable some warnings. Use // eslint-disable-next-line to igno ...
最新文章
- 【C语言】一文搞定如何计算结构体的大小----结构体内存对齐规则
- 举两个栗子:如何正确建立个人的机器学习项目集
- 使用internal(com.android.internal)和hidden(@hide)APIs – Part 5
- 问题集锦(21-25)
- MVP架构设计 进阶三
- 【Oracle】【日期、时间】 date与数字时间戳互转
- 80m的mysql文件要导入多久_mysql导入数据库文件最大限制更改解决方法:You probably tried to upload too large file...
- java面试常考系列四
- ARM汇编ADR,LDR等伪指令
- 年逾九十院士潘际銮:身背千亿科研价值身居斗室
- 【dfs】Election of Evil
- 信息学奥赛一本通C++语言——1053:最大数输出
- Django系列:(1)PyCharm下创建并运行我们的第一个Django工程
- PHP SEVER预定义变量
- (转)Cesium教程系列汇总
- Atlas中间件实现Mysql读写分离
- java远程桌面_java – 实现远程桌面共享解决方案
- 一个全网最详细 Python 教程,不信你来学一学!
- zabbix 报警	Lack of free swap space on Zabbix server 处理
- royal tsx连接闪退_Royal TSX for Mac(最强远程管理软件)