Nginx重试引发Http请求重复执行

PS:这个月还真的发现一笔订单请求服务端实际产生了两笔订单,听负责处理的同事说是Nginx方面的问题,准确的原因也没有解释详细,今天无意中看到此文,感到文章中的分析与此次线上问题情况符合,特地转载过来。


Nginx重试引发Http请求重复执行

蛙牛 发表于2016/12/05

https://my.oschina.net/lujianing/blog/785899

摘要: 前端提交一次,后端执行两次,通过日志分析,确定原因,Nginx重试机制引发Http请求重复执行

1.问题背景

web站点通过Nginx做反向代理,两个tomcat做负载均衡。

web站点有一个群发短信模块,管理员可以填写发送内容,手机号列表。点击发送,后台会执行群发短信操作,在发送结束后,返回发送结果。

在很早之前遇到过,重复发送的问题。最开始以为管理员异常操作,重复点击了发送按钮。因此对前端提交做了限制。在点击发送时,把按钮置为disable,执行完毕拿到返回数据,再置为可用,从前端限制重复提交。

今天突然有同事又使用到了这个模块,分别群发了两批短信(8000条和1600条),前端都提示了操作失败,但自己的手机却分别收到了重复的短信推送。

2.问题分析

首先确认了手机号列表没有重复,也通过浏览器调试确认前端没有发起重复请求。

通过查看两台服务器的日志,确实出现了重复的发送,且发送时间点不在同一时刻。

通过日志,可以估算出,发送一条短信的时间在10毫秒。 输入图片说明

也通过日志,查看到了处理超时日志,且发现了规律,重复的请求在不同机器处理且处理间隔时间相差一致

A日志

10:03:05,878  INFO TIMEOUT.info:252 - time: 75701ms, concurrent: 1, url: /push/sendmessage.
10:07:24,705  INFO TIMEOUT.info:252 - time: 15148ms, concurrent: 0, url: /push/sendmessage.

B日志

10:03:21,599  INFO TIMEOUT.info:252 - time: 76471ms, concurrent: 1, url: /push/sendmessage.
10:07:39,718  INFO TIMEOUT.info:252 - time: 15113ms, concurrent: 0, url: /push/sendmessage.

结合以上信息猜测,应该是请求执行时间超过限制,造成前端提示失败。重复的提交应该是重试机制造成。

于是联系运维进行确认。得到相关答复:

Nginx可以配置超时时间,假设配置15s,而一个请求需要16s才能处理完返回。Nginx路由到A服务器处理,A执行到第15s时,没有正常返回,Nginx会重新发到B服务处理,B执行到第15s时,也没有正常返回。前端等待30s,最后返回失败。A和B分别收到对应的请求,内部都进行了处理。

和运维同学确认过原因后,就可以根据相关信息自己搜索。

nginx的重试机制

文中也点到了一种解决方案,可以通过ip访问服务,绕过nginx。

另外我们的web站点,有一个下载的功能,在优化之前,每次下载的执行时间也很长,但是确没有遇到超时问题。分析了可能是GET和POST的区别。上文也给出了下面这个链接,确定大致思路。

http://serverfault.com/questions/528653/how-can-i-stop-nginx-from-retrying-put-or-post-requests-on-upstream-server-timeo

3.问题总结

通过网上的信息参考,Nginx可以对文件上传,下载,GET和POST请求设置不同的超时策略。

另外对于短信群发业务,其实有单独的模块,通过规则管理配置,做离线任务执行。现有保留的群发模块,只是为了应对小规模的业务。

展开阅读全文

没有更多推荐了,返回首页