一个线上紧急问题,有意思做了些测试和记录
背景描述:新上线一个比较复杂的批量功能,一次请求后台方法跑个2,3个小时不成问题,方法代码大致模式就是查询出表A中还没有处理的数据,循环数据集,对每行数据一番操作后保存到表B中,并标记表A本条数据已处理,事务每行一提交。
问题现象:表B中数据重复,有不重复的,有重复一次的,有重复两次及以上的
排查前猜想这数据样子肯定是重复请求,代码操作的时候没锁表A,一次请求执行了一半,又来了个请求,第二个请求查询当前还没处理的数据,这部分数据就会重复两次,再第三个第四个请求来,导致重复两次以上。代码确实有问题,没锁表,但是想肯定是用户开了多个功能做重复了啊,赖到用户身上先~
但是用户表情严肃:没人动,自始至终我只点了一下
懵圈,woc点了一下也会重复,http重发?我本地debug 一停就是一上午也没见重发请求啊,自己在生产环境试了一下,还真重复,过一段时间就会收到一个重复的http请求,因为是集群环境,所以怀疑是负载问题,带着发现找硬件F5,捣鼓好久发现F5超时参数配置的时长和重复请求间隔吻合,调长超时时间,问题解决。
F5我是没研究,也没接触过,我用nginx还原一下情况
Nginx重发请求测试
两台电脑,两个tomcat在一台,一个nginx在另一台
项目代码
RestController Get请求,睡眠30秒模拟业务耗时
两个tomcat上都部署的是这个程序,访问路径 /demo/testGet
Nginx配置
上边测试代码设置的超时为30s,nginx配置的超时就该比30s小,保证nginx超时重试时,代码还卡着
- keepalive_timeout 65; 与客户端keepalive的超时时间
- proxy_read_timeout 20; 与被代理的服务器 读超时时间,20s没有收到服务器发来的响应数据,nginx就断开
- proxy_send_timeout 20; 与被代理的服务器 写超时时间,20s没有发给服务器数据,nginx断开
- proxy_next_upstream error timeout; nginx失败重发机制的核心参数, 在error或者超时情况下,将请求传递给下一个服务器,可以自定义,例如可以设置服务器返回某个状态码的情况下传递
测试GET
在nginx那台电脑上用浏览器发起请求http://localhost:9258/demo/testGet
确实发现请求在两台tomcat上都来了一次,间隔20s
通过wireshark抓包也发现,两次HTTP,第一次请求和8080端口三次握手,过了20s,nginx发起FIN关闭socket,并与另一tomcat也就是8010端口三次握手建立连接并发起新的HTTP请求
测试POST
同样准备了一个Post方法,还是nginx那台电脑postman走一下http://localhost:9258/demo/testPost
不一样了,post只发了一次
度了度之后,知道nginx默认只会对幂等的http方法进行重发,幂等的例如(GET/DELETE/PUT),而POST是非幂等的,所以默认不会重发
如果业务需要重试post,需要对nginx的proxy_next_upstream参数追加non_idempotent,如下
proxy_next_upstream error timeout non_idempotent;
修改参数,nginx -s reload,再次发起post请求,可以看到与Get流程相同,新的http连接到8010端口
控制台都有输出