nginx超时重试机制及潜在的坑

本文地址:http://www.dutycode.com/nginx_chongshi_chongfuqingqiu.html
除非注明,文章均为 www.dutycode.com 原创,欢迎转载!转载请注明本文地址,谢谢。

问题描述:
有一个发送短信的http服务,客户端调用之后,只有一次请求,但是发了三次短信。

分析看:
     1、客户端仅发起了一次请求,
     2、服务端收到了三次请求
     3、三次请求分别落在了三台后端机器上。每台后端机器仅收到一次请求

基本的架构如下:
93914042-18CE-4EEB-BB84-C38756515AC1.png

分析及解决:
     分析代码,代码中没有重试机制,并且通过请求分布来看,并不是一台机器处理了三次,而是每台机器处理了一次。所以分析,可能是由于nginx转发导致。 
     查看接口的响应时间,发现每个接口的响应时间为18s左右(PS:由于是调用外部接口,此调用时间属于正常的时间。。。)。
     猜测是由于后端服务器未能及时返回数据,导致了nginx的超时重试机器,将请求分发到了另外一台机器上。
     查看nginx的配置文件,发现如下配置:
     
proxy_next_upstream http_502 http_504 error timeout invalid_header;

     上面的配置表示,如果后端服务器如下情况,将会把请求转发到下一台后端服务器上。
  • error - 在连接到一个服务器,发送一个请求,或者读取应答时发生错误。
  • timeout - 在连接到服务器,转发请求或者读取应答时发生超时。
  • invalid_header - 服务器返回空的或者错误的应答。
  • http_502 - 服务器返回502代码。
  • http_504 - 服务器返回504代码。
    
     继续查看超时时间
     
proxy_read_timeout 15;
 
   超时时间为15s,所以后端服务器响应慢,nginx没有在15s内收到返回的数据,所以将请求切换到下一台后端机器了,所以,同样的情况下, 请求第二台后端机器时,也没有在规定的时间内得到响应,所以又切换到第三台机器了,最终导致短信发送了三次。 

几个参数说明:

proxy_send_timeout     后端服务器数据回传时间(代理发送超时时间)
proxy_read_timeout      连接成功后,后端服务器响应时间(代理接收超时时间)
proxy_connect_timeout    nginx连接后端的超时时间,一般不超过75s


如何解决呢?
     1、第一种办法:因为后端机器无法再进行优化减少响应时间,所以可以更改nginx的超时时间,将原本的15s更改为40s,这样可以保证结果正常返回。
      2、第二种办法 :关闭自动切换到下台机器的功能,即将proxy_next_upstream配置为off。但是这样虽然能解决问题,但是会导致nginx的容错能力下降。
     3、第三种办法:从业务角度出发,本质上我们是需要只发一次短信的。 所以可以采用分布式锁的方式解决。


以上现象还可能出现在以下的场景:
1、上传excel,然后服务端处理excel内容,插入到db里面的时候,可能存在多次转发导致数据重复。
2、post请求处理时间过长,可能出现重复提交的问题。
 
posted @ 2022-02-28 15:34  甜菜波波  阅读(1471)  评论(0编辑  收藏  举报