[转帖]使用 nginx 作反向代理,启用 keepalive 时,遇到 502 错误的调查过程

使用,nginx,反向,代理,启用,keepalive,遇到,错误,调查过程 · 浏览次数 : 0

小编点评

**1.分析日志和原理推测** 根据日志和原理推测,可能存在以下两种可能有效的方案: ***nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时** ***nginx 的 keepalive_request 要小于 upstream 的相关设置** **2.建议** 建议降低并发数量,排除端口耗尽的情况。例如,可以降低 maxKeepAliveRequests 的值,或者可以降低 keepalive_request 的值。 **3.分析日志和原理推测** 根据日志和原理推测,可能存在以下两种可能有效的方案: ***nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时** ***nginx 的 keepalive_request 要小于 upstream 的相关设置** **4.建议** 如果无法降低并发数量,可以尝试降低 maxKeepAliveRequests 的值,或者可以降低 keepalive_request 的值。也可以尝试降低 keepalive_request 的值。 **5.分析日志和原理推测** 根据日志和原理推测,可能存在以下两种可能有效的方案: ***nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时** ***nginx 的 keepalive_request 要小于 upstream 的相关设置** **6.建议** 如果无法降低并发数量,可以尝试降低 maxKeepAliveRequests 的值,或者可以降低 keepalive_request 的值。也可以尝试降低 keepalive_request 的值。 **7.分析日志和原理推测** 根据日志和原理推测,可能存在以下两种可能有效的方案: ***nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时** ***nginx 的 keepalive_request 要小于 upstream 的相关设置** **8.结论** 根据日志和原理推测,可能存在以下两种可能有效的方案: ***nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时** ***nginx 的 keepalive_request 要小于 upstream 的相关设置**

正文

https://www.cnblogs.com/lizexiong/p/15358894.html

 

 

1.现象

  结论见 《kubernetes ingress-nginx 启用 upstream 长连接,需要注意,否则容易 502》。nginx 的访问日志间歇性出现 502 响应,查看 nginx 的 error.log,发现是 upstream 返回了 reset:

复制代码
2019/06/13 04:57:54 [error] 3429#3429: *21983075 upstream prematurely closed connection while reading 
response header from upstream, client: 10.19.167.120, server: XXXX.com, request: "POST XXXX HTTP/1.0",
upstream: "http://11.0.29.4:8080/XXXXXX", host: "XXXX.com"
 
2019/06/13 04:58:34 [error] 3063#3063: *21989359 recv() failed (104: Connection reset by peer) while 
reading response header from upstream, client: 10.19.138.139, server: XXXX.com, request: 
"POST /api/v1/XXXX HTTP/1.1", upstream: "http://11.0.145.9:8080/api/v1/XXXX", host: "XXXX.com"
复制代码

 

2.调查

  在 nginx 上抓包,nginx 向 upstream 发送请求后,upstream 直接返回 reset,nginx 回应 502,触发 reset 的请求的发送时间比上次晚了 1 分钟以上:

  

  检查其它正常响应的连接,发现服务端会在连接闲置 1 分20 秒的时候,主动断开连接:

  

  奇怪的是 nginx 设置的 keepalive_timeout 为 60 秒,为什么不是 nginx 主动断开连接?

 

3.验证第一个假设:服务端 idle 先超时会引发 reset

  猜测 upstream 对应的服务端也设置了超时时间,并且比 nginx 先超时,因此出现了服务端率先断开连接情况。如果服务端断开连接时,nginx 正好向 upstream 发送了请求,就可能出现 reset 的情况。

  部署一个服务端容器,服务端的 idle 超时设置为 10 秒,小于 nginx 中配置的 keepalive_timeout (60秒)。用 httpperf 模拟 100 个会话,每个会话以每间隔 9 秒发送 100 个请求的方式累计发送 300 个请求,会话创建速率是每秒 10 个。

httperf --server webshell.example.test --port 80 --wsess 100,300,9 --burst-len 100 --rate 10
./httperf --server webshell.example.test --port 80 --wsess 1,256,9 --burst-len 128 --rate 1

  遗憾的是 httperf 太老旧支持的量太少,没能复现出来。假设的场景本身也很难复现,必须恰好在连接因为超时关闭时发送请求,比较难复现。

  另外找到三篇文章都在讨论这个问题:

  1.104: Connection reset by peer while reading response header from upstream

  2.HTTP 502 response generated by a proxy after it tries to send data upstream to a partially closed connection (reset packet)

  3.Analyze ‘Connection reset’ error in nginx upstream with keep-alive enabled

 

4.发现新情况

  有用户反应能够稳定复现 502,且是在压测期间发现的,这就奇怪了。idle 超时导致的 502 应该很难出现,能稳定复现 502 肯定是有其它原因。

  在继续调查的过程中,首先想到的是「长连接中的最大请求数」,服务端会不会设置了单个连接中能够处理的请求数上限,并且该上限小于 nginx 中的配置?

  公司的业务系统主要是 tomcat 服务,因此优先调查 tomcat 的配置,发现了下面的参数:

  tomcat 默认每个连接中最多 100 个请求,而 nginx 中配置的 keepalive_requests 超过了 100,这会不会是问题根源?需要测试验证一下。

  同时发现 tomcat 默认的 idle 超时时间是 60s,和前面提出的超时假设能够相呼应,tomcat 7 和 tomcat 8 的使用的是相同的默认配置。Tomcat Config

  

 

5.验证第二个假设:服务端率先断开连接导致502

  部署一个 tomcat 服务,idle 超时时间为 60s,maxKeepAliveRequests 为 100,nginx 的 idle 超时为 60s,keepalive_requests 为 2000,用下面的命令压测:

./wrk -t 4  -c 10000 -d 90s http://ka-test-tomcat.example.test/ping

  10000 并发压测 90s 时,出现 502 响应:

  然而从报文发现:服务端直接 reset 的连接数是 24 个,数量远远低于 502 响应的数量。

  怀疑还有其它原因,检查 nginx 发现大量下面的日志:

2019/06/17 09:35:46 [crit] 28805#28805: *9114394 connect() to 10.12.4.197:8080 failed (99: Cannot assign requested address) while connecting to upstream, client: 10.10.173.203, server: ka-test-tomcat.example.test, request: "GET /ping HTTP/1.1", upstream: "http://10.12.4.197:8080/ping", host: "ka-test-tomcat.example.test"
2019/06/17 09:35:46 [crit] 28806#28806: *9114649 connect() to 10.12.4.197:8080 failed (99: Cannot assign requested address) while connecting to upstream, client: 10.10.173.203, server: ka-test-tomcat.example.test, request: "GET /ping HTTP/1.1", upstream: "http://10.12.4.197:8080/ping", host: "ka-test-tomcat.example.test"
2019/06/17 09:35:46 [crit] 28804#28804: *9114172 connect() to 10.12.4.197:8080 failed (99: Cannot assign requested address) while connecting to upstream, client: 10.10.173.203, server: ka-test-tomcat.example.test, request: "GET /ping HTTP/1.1", upstream: "http://10.12.4.197:8080/ping", host: "ka-test-tomcat.example.test"

  统计了一下,crit 日志数和 502 响应的数量级相同,断定本次压测中产生大部分 502 是 nginx 上的端口不足导致的,又发现了一种导致 502 原因:nginx 的端口耗尽 。

  尝试降低并发数量,排除端口耗尽的情况:

./wrk -t 4  -c 500 -d 300s http://ka-test-tomcat.example.test/ping

  结果比较悲催,无论如何也没有 502,检查报文发现有少量服务端回应的 RST 报文,是在发起了 FIN 连接后再次回应的。而在多次压测过程中,又的确出现过两次总计100多条的 104: Connection reset by peer日志,但就是复现不出来,不知道是它们在什么情况下产生的……

 

6.新的发现

  有点陷入僵局,回头审视反应能够稳定复现 502 的用户的系统,最后一个请求与上一个请求的间隔时间是 2 秒。

  这个 2 秒的时间差一开始带来了困扰,也正是这个 2 秒的时间差,让我怀疑之前的超时断开假设不成立,调头去查 maxKeepAliveRequests 的问题。

  进入用户的系统后,发现后端服务是用 Gunicorn 启动的 python 服务,查阅 Gunicorn的配置,发现它默认的 keepalive 时间是 2秒,正好和报文中的情况对应。

  也就是说,能够稳定复现的 502 也是因为服务端先触发 idle 超时,之所以能够稳定触发,因为后端服务的配置的超时时间只有 2秒,而请求端又恰好制造出静默两秒后发送下一个请求的场景。

  超时断开应该比超过 maxKeepAliveRequests 断开更容易引发 502,因为超过 maxKeepAliveRequests 时,会在最后一个请求结束后立即发送 FIN 断开连接,不容易与 nginx 正在转发的请求「撞车」,而超时断开可能在任意时刻发生,可能正好是 nginx 收到新的请求的时候,转发新请求时与服务端关闭连接的操作「撞车」。

 

7.初步结论

  根据日志和原理进行推测,提出两个可能有效的方案:

  1.nginx 的 keep-alive 的 idle 超时要小于 upstream 的 idle 超时;

  2.nginx 的 keepalive_request 要小于 upstream 的相关设置。

  以上两个配置可以保证连接断开都是 nginx 发起的,从而可以避免向一个已经关闭的连接发送请求。

 

8.转载

https://www.lijiaocn.com/%E9%97%AE%E9%A2%98/2019/06/13/nginx-104-reset.html#本篇目录

与[转帖]使用 nginx 作反向代理,启用 keepalive 时,遇到 502 错误的调查过程相似的内容:

[转帖]使用 nginx 作反向代理,启用 keepalive 时,遇到 502 错误的调查过程

https://www.cnblogs.com/lizexiong/p/15358894.html 1.现象 结论见 《kubernetes ingress-nginx 启用 upstream 长连接,需要注意,否则容易 502》。nginx 的访问日志间歇性出现 502 响应,查看 nginx 的

[转帖]使用nginx的proxy_store缓存文件加速访问速度

https://www.qiansw.com/using-nginxs-proxystore-cache-file-to-accelerate-access-speed.html nginx的proxy_store可以将后端服务器的文件暂存在本地. 基于此,可以实现nginx的缓存后端服务器文件,加

[转帖]使用SkyWalking监控nginx (以openresty为例)

https://www.cnblogs.com/hahaha111122222/p/15829737.html 安装使用SkyWalking先看这篇文章,地址:https://www.cnblogs.com/sanduzxcvbnm/p/15829781.html 使用SkyWalking监控ngi

[转帖]Nginx 使用与异常处理

http://jartto.wang/2017/04/15/nginx-exception-handling/ 以前总是偷懒使用 Http-Server 来启动一个本地服务,后来花时间学习了一下 Nginx,感觉挺好用。总结整理一下,就当打点存档了。 一、简单介绍 Nginx — Ngine X,是

[转帖]prometheus监控nginxt的两种方法(vts)

方法一 使用nginx_ vts_exporter mkdir -p /data/nginx/{log,conf/conf.d} cat > /data/nginx/conf/nginx.conf << 'EOF' user root; worker_processes auto; error_lo

[转帖]【官方文档】Nginx负载均衡学习笔记(三) TCP和UDP负载平衡官方参考文档

本章介绍如何使用NGINX Plus和NGINX开放源代理和负载平衡TCP和UDP流量。 目录 介绍先决条件配置反向代理配置TCP或UDP负载平衡被动健康监控 选择负载平衡方法配置会话持久性 主动健康监控 怎么运行的先决条件基本配置微调健康检查使用匹配配置块进行微调健康检查 TCP的微调健康检查UD

[转帖]nginx 的超时设置

前言 我们在使用nginx做反向代理的时候,可能会遇到这个场景:后端正常的业务处理时间超过了nginx的超时时间,导致nginx主动返回504。为解决这个问题,我们网上搜索发现可以通过调整这几个参数来调大nginx的超时时间。 proxy_connect_timeout proxy_send_tim

[转帖]Nginx反向代理中使用proxy_redirect重定向url

https://www.cnblogs.com/kevingrace/p/8073646.html 在使用Nginx做反向代理功能时,有时会出现重定向的url不是我们想要的url,这时候就可以使用proxy_redirect进行url重定向设置了。proxy_redirect功能比较强大,其作用是对

[转帖]Kubernetes的Nginx Ingress 0.20之前的版本,upstream的keep-alive不生效

https://www.cnblogs.com/lizexiong/p/15358923.html 1说明 Kubernetes使用nginx-ingress-controller代理到集群内服务的请求,nginx所在的机器上上有大量的time-wait连接。 抓包发现nginx发起的到upstre

[转帖]无涯教程: Nginx - HTTP负载平衡介绍

https://www.imooc.com/article/318916 集群代理池 在开始使用Nginx或Nginx Plus负载均衡HTTP流量到一组服务器之前,首先,我们需要使用上游(upstream)指令定义该组。该指令位于http上下文(context)中。 使用server指令配置组中的