NGINX代理返回代码499问题分析与处理
Posted 王小那个鑫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NGINX代理返回代码499问题分析与处理相关的知识,希望对你有一定的参考价值。
一、背景
我们通过nginx作为互联网代理服务器,通过它实现我行内部系统向互联网系统的接口访问及调用;但是在使用过程中,不时的会出现大量返回代码为499的问题(正常访问返回为200),甚至有时候部分系统在报499的错误时,会影响到某一业务的正常使用。此时,我们也会怀疑nginx代理出现了问题,于是重启或者重新加载nginx服务。但是比较奇怪的是,如果nginx整个出现了问题,那么为什么会出现某个业务异常而不是在nginx上的所有服务异常呢?于是,我们则需要对为什么nginx会返回499错误代码展开分析和研究。
二、499代码代表了什么
nginx返回499错误,那么我们就到nginx的源码里面看看,是否存在499返回代码的解释呢?通过在nginx的源码进行查找,发现有一段这样的代码:
#define NGX_HTTP_LAST_4XX 430
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
ngx_string(ngx_http_error_494_page), /* 494, request header too large */
ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
ngx_string(ngx_http_error_497_page), /* 497, http to https */
ngx_string(ngx_http_error_404_page), /* 498, canceled */
ngx_null_string, /* 499, client has closed connection */
ngx_string(ngx_http_error_500_page),
ngx_string(ngx_http_error_501_page),
ngx_string(ngx_http_error_502_page),
ngx_string(ngx_http_error_503_page),
ngx_string(ngx_http_error_504_page),
ngx_string(ngx_http_error_505_page),
ngx_null_string, /* 506 */
ngx_string(ngx_http_error_507_page)
从这里,我们则可以看到ngx_null_string对应的就是499代码,其表示了client has closed connection,即说明了是客户端已经关闭了连接。
那么为什么客户端会主动去关闭连接呢?其实最简单的解释就是因为服务端处理时间过长,然后客户端无法等到服务端处理完成,然后就会去主动关闭连接,然后代理就会为我们返回499错误。
在进行资料查询后,我们可以总结出一般有几种情况,可能造成499错误:
1)客户端在服务端响应前确实主动关闭了连接;
2)客户端在连接服务端进行业务的过程中,网络发生了中断,出现了连接超时;
3)两次提交post过快,nginx会认为是不安全的连接,主动拒绝了客户端的连接(往往是有人故意攻击,消耗服务器资源);
4)php的进程数量不够用,需要调整php的进程数量;
三、如何处理499问题
在nginx的配置中有一个参数为:proxy_ignore_client_abort
该参数的含义是:确定在客户端关闭连接时,是否关闭与代理服务器的连接,而不再等待响应。
该值的默认值为off,此时则代表在发生交易的过程中,如果客户端无论是发生了主动关闭连接、客户端网络中断、访问服务超时、服务器未处理的情况,那么 Nginx 都会记录 499;这样则可能会存在一个问题就是可能无法真实反应客户端服务访问的真实情况。
而该值改为on的时候,则表示客户端主动断掉连接之后,Nginx 会等待后端服务器处理完(或者超时),然后记录“后端的返回信息”到日志。因此,会有几种情况:
1、如果后端返回200,就记录200 ;
2、如果后端返回5XX ,那么就记录 5XX;
3、如果超时(默认60s,可以用 proxy_read_timeout 和proxy_send_timeout设置),Nginx 会主动断开连接,记录504。
这样则可以将访问异常的真实问题反应出来。
因此,我们可以通过在http域、server域、location域内加入:
```
proxy_ignore_client_abort on
```
四、风险
根据上面的分析,其实我们可以发现,其实发生499的问题时候的可能性会很多,而且如果出现客户端在建立连接后主动关闭了连接的情况则会是一种正常的场景。当然,虽然我们可以通过打开proxy_ignore_client_abort的参数来解决499的问题,且可以暴露出客户端到服务端的真实原因。但是打开该设置后也会存在一定风险,即当有大量瞬间断开的请求时,后端会默默地全部处理掉,比较浪费资源,且并发压力比较大时,也有可能造成服务器出现被压垮宕机的可能。
五、结论
结合上述的分析,考虑到风险,我们可以得出以下结论,如果我们的机器只存在单机环境或者无冗余环境的时候,我们尽可能的不要去设置这个参数,从而避免服务器被压垮的风险;当我们有足够的环境做冗余的时候或者在前端有负载均衡对连接进行分发负载的时候,我们则可以考虑打开该参数,从而便于运维人员分析问题异常。
10. Nginx实现反向代理
参考技术A反向代理: reverse proxy, 指的是代理外网用户的请求到内部的指定的服务器, 并将数据返回给用户的一种方式, 这是用的比较多的一种方式
Nginx除了可以为企业提供高性能的web服务之外, 另外还可以将Nginx本身不具备的请求通过某种预定义的协议转发至其他服务器处理, 不同的协议就是Nginx服务器与其他服务器进行通信的一种规范, 主要在不同的场景使用以下模块实现不同的功能
生成环境部署架构:
访问逻辑图:
Nginx反向代理http服务:
1. proxy_pass
2. proxy_hide_header field
修改前, 响应报文头部会携带ETag信息
修改后ETag信息被隐藏
3. proxy_pass_header field
4. proxy_pass_request_body
5. proxy_pass_request_headers
6. proxy_set_header
由于proxy_set_header只是修改了请求报文的头部信息, 添加了自定义的字段, 因此, 还需要在后端服务器修改日志定义格式, 才能方便将客户端ip记录到日志信息中
注意1:通过set_proxy_header自定义变量只是给请求报文添加了一个自定义的字段, 其字段值是人为根据系统内置变量设定的
注意2: 这种方法, 在多级代理的情况下, 并不能将客户端ip, 逐层的传给后端服务器, 而是需要利用$proxy_add_x_forwarded_for变量实现
注意3: 如果一定要使用proxy_set_header去传递客户端ip和每一层代理的ip地址, 那么需要在每一层nginx代理都开启proxy_set_header, 并且设置不同的自定义变量去引用nginx自带变量$remote_addr, 这样每一级nginx都会记录上一级, 也就包括客户端的ip地址, 同时, 在后端服务器的日志格式中, 要添加多个nginx自定义的变量, 这样也可以把客户端ip和中间经过的代理的ip全部传递给后端的服务器
proxy_add_x_forwarded_for实现多级代理ip地址透传示例: 需要在每一级代理都开启
实验环境:
7. 有关反向代理时间的几个参数
8. proxy_ignore_client_abort
9. hash表大小的设置
客户端 ----- http协议 ------- nginx(代理服务器,10.0.0.86) ----- http --- apache (10.0.0.85)
客户端, 通过访问nginx上定义的虚拟主机中的server_name域名, 通过内部定义的location匹配规则, 被转发到10.0.0.85服务器
代理服务器与后端服务器连接出现问题可能发生的报错:
如果后端服务器想把图片资源放到固定的目录下, 也可以自定义, 比如存到/var/www/html/static, 那么nginx的location就要修改为如下:
缓存功能相关参数:
实验环境:
proxy_pass 可以让Nginx将客户端请求转发至后端单台服务器, 但是无法转发至特定的一组服务器, 而且不能对后端服务器提供相应的服务器状态监测.
Nginx可以基于 ngx_http_upstream_module 模块提供服务器分组转发, 权重分配, 状态监测, 使用不同的调度算法等高级功能
关于ip_forward
注意: 本实验过程要先关闭缓存
访问固定的URI会被调度到相同的服务器
以上是关于NGINX代理返回代码499问题分析与处理的主要内容,如果未能解决你的问题,请参考以下文章