nginx499状态码产生的原因

技术文档网 2021-04-19
什么是 nginx 的 499

499 是 nginx 扩展的 4xx 错误,目的只是用于记录,并没有实际的响应。
看一下 nginx 源码 ngx_http_request.h 对 499 的定义:

/*
* HTTP does not define the code for the case when a client closed
* the connection while we are processing its request so we introduce
* own code to log such situation when a client has closed the connection
* before we even try to send the HTTP header to it
*/
#define NGX_HTTP_CLIENT_CLOSED_REQUEST     499

由上述表述可知,nginx 499 代表客户端请求还未返回时,客户端主动断开连接。

什么情况下 nginx 记录 499

通过网上查询相关资料学习与了解,自己总结大致原因就是请求在指定的时间内没能拿到响应而关闭了连接。问题症结点为两处:1、指定的时间;2、程序处理的性能。

时间问题

最开始时,表述过 nginx 499 是客户端主动断开了连接。这里的客户端概念,我的理解是对请求连接过程中的下游服务而言的,例如浏览器与 nginx 之间的连接,浏览器为客户端;nginx 与其分发的服务而言,nginx 是客户端;php 处理程序中发起的 curl 请求而言,php-fpm 可视为客户端。
上述的指定时间内的这个时间,一般是定义的处理超时时间,可能的原因就是这个时间设短了。
以发起 curl 请求为例,数据传输的最大允许时间用 -m 参数来指定。
例如:
curl -m 20 "http://somewebsite.com"
数据传输的最大允许时间超时的话,curl 断开了请求,而 web 服务器如 nginx 还在处理的话,则 nginx 会记录 499;

再如 nginx 作为反向代理时,nginx 将请求分发至对应的处理服务器时,有两对超时参数的设置:proxy_send_timeoutproxy_read_timeout ; fastcgi_send_timeoutfastcgi_read_timeout
两对参数分别对应的是 ngx_http_proxy_module 和 ngx_http_fastcgi_module 模块的参数。两对参数默认的超时时间都是 60 s。在 nginx 出现 499 的情况下,可以结合请求断开前的耗时和这两对设定的时间进行对比,看一下是不是在 proxy_pass 或者 fastcgi_pass 处理时,设置的超时时间短了。

再如 php 操作超时。打开 php.ini 查看 max_execution_timemax_input_time 两个参数。两者分别是 php 程序执行的最长时间和表单提交的最长时间。

如果后端服务中访问了负载均衡的,例如 AWS 上的 Elastic Load Balances 等。出现 nginx 上设置的超时很大,nginx 同样记录了 499 状态,那么有可能就是负载均衡在默认时间(一般是 60 s)后删除了连接。这种情况下,可根据 nginx 的配置,相应的修改负载均衡的配置。

性能问题

性能问题就比较宽泛了,不太便于排除,可能会有的情况:
1、CPU 和内存的使用情况
linux 上,可以用 top 命令查看 CPU 和内存的使用情况。

top - 16:59:03 up 334 days, 23:10,  1 user,  load average: 0.06, 0.08, 0.07
Tasks: 114 total,   2 running, 112 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.5 us,  0.3 sy,  0.0 ni, 98.5 id,  0.7 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  2916192 total,   516184 free,  1540972 used,   859036 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   999988 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
11475 work      20   0  157680   2188   1520 R   0.7  0.1   0:00.34 top
12206 elastic+  20   0 3685272 980.1m    272 S   0.7 34.4   1027:58 java
24451 mysql     20   0 1745372 275176   2892 S   0.3  9.4 761:20.55 mysqld
    1 root      20   0  232328  46328   1324 S   0.0  1.6  33:03.32 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.80 kthreadd
    3 root      20   0       0      0      0 S   0.0  0.0   0:37.02 ksoftirqd/0
    5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H
    7 root      rt   0       0      0      0 S   0.0  0.0   0:20.47 migration/0
    8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh
    9 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcuob/0
   10 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcuob/1
   11 root      20   0       0      0      0 R   0.0  0.0 126:24.86 rcu_sched

第三行,cpu状态信息,具体属性说明如下:

0.5% us — 用户空间占用CPU的百分比;
0.3% sy — 内核空间占用CPU的百分比;
0.0% ni — 改变过优先级的进程占用CPU的百分比;
98.5% id — 空闲CPU百分比;
0.7% wa — IO等待占用CPU的百分比;
0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比;
0.0% si — 软中断(Software Interrupts)占用CPU的百分比。

第四行,内存状态,具体信息如下:

2916192k total — 物理内存总量(2.9GB);
1540972k used — 使用中的内存总量(1.5GB);
516184k free — 空闲内存总量(0.5GB);
859036k buffers — 缓存的内存量 (859M)。

2、php-fpm 等 fastcgi 处理程序进程数不够用
需要理解的参数有: pm、pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers。
pm 表示进程数的控制方式,分别为 static (静态)和 dynamic (动态)。

pm = dynamic 如何控制子进程,选项有static和dynamic
pm.max_children:静态方式下开启的php-fpm进程数量
pm.max_requests:php-fpm子进程能处理的最大请求数
pm.start_servers:动态方式下的起始php-fpm进程数量
pm.min_spare_servers:动态方式下的最小php-fpm进程数
pm.max_spare_servers:动态方式下的最大php-fpm进程数量

3、mysql 等数据查询过程缓慢
MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10S以上的语句。默认情况下,Mysql数据库并不启动慢查询日志,需要我们手动来设置这个参数。具体可参考Mysql 慢查询日志总结

4、程序处理逻辑性能不好
这一项需要查询程序的逻辑处理是否有过多的重复的或者冗余的过程了。:smile:

他人给的解决方案

网上能查询到的解决方案基本就是在 nginx.conf 的 http 块中添加 proxy_ignore_client_abort on;
默认的情况下该参数是关闭的。nginx 官网给的参数说明如下:

Determines whether the connection with a proxied server should be closed when a client closes the connection without waiting for a response.

主要意思就是在客户端主动关闭连接后, nginx 与分发服务器的连接是否保持连接。
如果使用了 proxy_ignore_client_abort on; Nginx 会等待后端处理完(或者超时),然后记录「后端的返回信息」到日志。所以,如果后端返回 200,就记录 200 ;如果后端放回 5XX ,那么就记录 5XX 。
如果超时(默认60s,可以用 proxy_read_timeout 设置),Nginx 会主动断开连接,记录 504。
上述方法,个人认为仅仅是解决了 nginx 记录 499 的问题,并没有从本质上解决客户端没能拿到请求响应的问题,具体还是得从超时时间的设定和程序处理性能的提升上从根本解决问题。


总结参考自
[1]:Linux top 命令
[2]:php-fpm 进程数优化

相关文章

  1. app多版本的服务端部署

    背景 手机客户端按一定周期发版,但是客户不一定会及时更新到最新版本,所以需要服务端能支持旧版手机客户端。 服务端支持旧版手机客户端的方式主要有: 相同的接口支持不同版本手机端的请求,需要服务端接口

  2. 反向代理时URI的处理

    当使用proxy_pass的时候,请求的URI传递给服务器是有一定的规则的。 proxy_pass带有URI 比如下面的配置: location /name/ { proxy_pass htt

  3. nginx-echo-命令引发的探索

    起因 最初在 nginx.conf 中调试时,当时希望 echo 出对应的变量值,并没有成功。起初认为是 nginx 安装时,并没有安装 echo 模块,然而事后发现实际用的是 openresty,o

  4. nginx499状态码产生的原因

    什么是 nginx 的 499 499 是 nginx 扩展的 4xx 错误,目的只是用于记录,并没有实际的响应。看一下 nginx 源码 ngx_http_request.h 对 499 的定义:

  5. Nginx配置文件参数说明

    定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU数量*核数。 worker_processes 8; 全局错误日志定义类型,[ debug |

随机推荐

  1. app多版本的服务端部署

    背景 手机客户端按一定周期发版,但是客户不一定会及时更新到最新版本,所以需要服务端能支持旧版手机客户端。 服务端支持旧版手机客户端的方式主要有: 相同的接口支持不同版本手机端的请求,需要服务端接口

  2. 反向代理时URI的处理

    当使用proxy_pass的时候,请求的URI传递给服务器是有一定的规则的。 proxy_pass带有URI 比如下面的配置: location /name/ { proxy_pass htt

  3. nginx-echo-命令引发的探索

    起因 最初在 nginx.conf 中调试时,当时希望 echo 出对应的变量值,并没有成功。起初认为是 nginx 安装时,并没有安装 echo 模块,然而事后发现实际用的是 openresty,o

  4. nginx499状态码产生的原因

    什么是 nginx 的 499 499 是 nginx 扩展的 4xx 错误,目的只是用于记录,并没有实际的响应。看一下 nginx 源码 ngx_http_request.h 对 499 的定义:

  5. Nginx配置文件参数说明

    定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU数量*核数。 worker_processes 8; 全局错误日志定义类型,[ debug |