首页 > 编程知识 正文

nginx502,nginx出现502如何解决

时间:2023-05-03 15:07:40 阅读:21842 作者:500

我们的一个web项目是新城增加,访问量增加,数据库压力增大,作为提供接口的运营商,最近下游反馈大量要求“502”。

502,bad gateway通常是upstream (在本例中为php )错误。 对于php,502的常见原因是脚本运行超过了timeout的设置时间,或者timeout的设置时间太长,导致php进程长时间无法释放,空闲的工作器进程无法迎接客人。

我们的项目是因为php运行时间设置得太短,针对这种情况,可以先适当增加php运行时间,保证先完成502,优化毕竟需要更多的时间。

有两个选项可以控制php的运行时间。 在php.ini中为max_execution_time,在php-fpm中为request_terminate_timeout。 其中request_terminate_timeout

接下来,我们将详细分析为什么当php脚本运行超过设置时间时,nginx会返回502。

首先来主题,再现问题:

nginx和php各自只启动一个工作器,便于跟踪。

php-fpm的request_terminate_timeout设置为3S。

测试脚本test.php

ogogo(go ) :

通过浏览器访问www.v.com/test.php,3S后按计划. 404? 微信?

老师很不利啊。 现在我们来看看nginx的配置文件

此location配置在发生5xx错误时会跳转到干净的接口,但在/usr/share/nginx/html下没有名为50x.html的文件。 所以做了404。 这不是对我判断问题的正确性影响不大吗? 直接注释掉! 再次访问,等待3S,终于出现了“正常”的接口。

环境就绪后,接下来就上模子了。 按照web问题故障排除的类型再走一遍。 首先查看错误日志:

nginx:

所有错误都是recv () failed ) 104:连接resetbypeer。

recv期间失败,连接复位。 为什么连接重置了? 一言不合吗?

查看php-fpm错误日志:

(注意在php-fpm的php_admin_value[error_log]选项中指定php错误日志将复盖php.ini中的。 但这里看到的不是php的错误,而是php-fpm的错误。 php-fpm错误日志由php-fpm.conf中的error_log选项指定。 )

每个请求生成两个警告和一个通告。

WARNING :脚本执行超时。 结束了。

警告:子进程收到SIGTERM信号后终止。

NOTICE :新的子进程开始了。 (因为我设定的pm.min_spare_servers=1) )。

如果php工作器进程运行超时,则工作器进程似乎不仅会停止脚本运行,而且也会停止运行。 nginx错误通知连接被重置可能是因为php工作器进程结束。 (如果在TCP连接期间一个断开,RST将发送到另一个。 )

在日志中,您可以看到php脚本运行超时,worker子进程终止,nginx在Connection reset by peer中报告了错误。 接下来,让我们来看看strace中php和nginx的情况。

php :

1.accept的一个nginx连接请求(socket、bind、listen均在master上完成),显示nginx的端口为47039。 从FD0读取数据是从标准输入,这在fast-cgi协议中有所规定。 accept之后的连接描述符是3。

从FD3读取nginx传递的数据,以fastcgi协议格式接收856字节。 为什么read5是5次?

fastcgi协议包是8字节对齐的,因此由包头和包主体组成。 都是先发送包含请求ID、版本、typpe等信息的请求包,包主体各8字节。 另外,发送1个数据包主体,传递get参数和环境变量,数据包主体为8字节,数据包主体变长。 最后没有数据包主体,只发送数据包主体的数据包主体,表示数据包主体的发送结束。 这样,前三个read用于读取请求分组的报头和分组主体以及params分组的报头,第四个read读取真实数据,而最后一个read读取最后一个params分组因此,nginx传输的数据为8 8 8 856 8=896字节(与以下nginx的传输字节对应)。 注意对于开机自检方式,还会发送stdin数据包。

3 .休眠20S设置为php程序中的sleep(20 ),之后该过程结束,因此没有后续

啦。strace程序也退出啦。

nginx:

1.accept到浏览器的请求,可以看到浏览器端的端口是56434,IP是192.168.1.105,已建立连接的FD是3。

2.从FD3中接收数据,HTTP协议。

3.创建一个socket,FD21,用于和php建立连接。

4.连接到FD21,可以看到连接的是本机的9000端口,这里nginx和php-fpm使用IP socket连接方式,nginx和php-fpm部署在一台机器上可以考虑unix domain socket。

5.向FD21写入数据,fast-cgi协议格式,我们看到写入的长度是896,和上边的php接收的长度是对应的。

6.recvfrom函数从FD21中返回 ECONNRESET (Connection reset by peer)

7.向FD9中写入错误信息,可以推断FD9就是nginx错误日志的文件描述符。

8.关闭和FD21的连接。

9.向FD3写入502 Bad Gateway,就是返回给浏览器的信息。

10.向FD8写入一条访问日志,可以推断FD8就是nginx访问日志的文件描述符。

来验证一下nginx访问日志和错误日志的推断。可以看到的确是FD8,FD9,并处于写入模式。

那么在这个过程中整个网络包的传输我们不妨也看一下:

通过tcpdump抓包,用神器看比较方便。

因为只想看nginx和php的通讯,在上边又知道nginx的端口是47039,可以通过tcp.srcport==47039过滤出对应的包。

可以看到nginx和php-fpm数据交互的过程:47039->9000建立三次握手,接着向9000发送数据,9000回复ACK,3S后9000回复RST。没毛病。

注意:

SYN,FIN各占一个序列号

ACK,RST不占序列号(28,29两个包的reqnum和acknum都是相同的)

序列号是每一字节加1(29包发送896字节,同时29包seq为4219146879,30包的ack为4219147775,正好相差896)

RST不需要回复。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.cnblogs.com/leezhxing/p/6220879.html

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。