记一次Ribbon重试配置不生效问题
问题发生:
生产环境发现一个交易订单对应两个支付订单记录(按实际业务应该一对一)
问题排查:
业务服务在调用支付服务时候是使用Feign来调用接口的(只接收post请求),配置中有重试相关配置(配置如下),由于网络原因,支付服务在10s后没有返回响应,触发了重试机制,导致出现了两个支付订单的情况。
1 | true = |
问题模拟:
retry.enabled | MaxAutoRetries | MaxAutoRetries | OkToRetryOnAllOperations | 实验结果 |
---|---|---|---|---|
false | 1 | 1 | true | 重试4次后,抛出SocketTimeoutException异常 |
false | 1 | 1 | false | 重试4次后,抛出SocketTimeoutException异常 |
true | 2 | 1 | false | 重试6次后,抛出SocketTimeoutException异常 |
true | 2 | 2 | false | 重试9次后,抛出SocketTimeoutException异常 |
true | 1 | 1 | true | 重试4次后,抛出SocketTimeoutException异常 |
问题分析
从上面的模拟结果可以看两点问题(第3点没在表格列出来):
1、spring.cloud.loadbalancer.retry.enabled
跟 ribbon.OkToRetryOnAllOperations
两个参数不管配置成 true
还是 false
。都会进行重试。
2、ribbon.MaxAutoRetries
跟 ribbon.MaxAutoRetriesNextServer
参数改变,会改变重试的次数。
3、ribbon.ReadTimeout
的改变会影响重试间隔时间(这个没在表格中列出来,但是确实会影响)。
问题解决:
查阅了一些资料,以及在网上找了很多博客对spring cloud重试机制的讲解,发现配置并没有问题,所以问题应该不在配置上。
又经过一番对比,发现很多文章包括spring官方文档都有说到,需要引入spring-retry
依赖,于是查看项目依赖,果然没有引入该依赖,把依赖引入后问题得到解决。
总结与思考
许多问题的解决方法往往就在眼前,但是时常会被忽略。同时也具有一定的迷惑性,在解决这个问题的过程中,首先因为配置的关系,部分配置是生效的,另一部分没生效,所以会让人搞不清楚是哪里出现的问题。另外,网上找了些文章,里面有说道spring.cloud.loadbalancer.retry.enabled
配置默认是关闭的,也就是false,但是我在查阅源码的时候发现,源码(源码如下)里面默认是true,这也让我有点迷惑。所以一开始对引入spring-retry
依赖的问题也就忽略了,想着是不是版本更新后这个默认就不需要引入了,也因此陷入了这样一个误区,在兜兜转转一圈后才发现问题所在。
1 | "spring.cloud.loadbalancer.retry") ( |
参考资料
1、https://cloud.spring.io/spring-cloud-netflix/multi/multi_retrying-failed-requests.html
2、https://blog.didispace.com/spring-cloud-ribbon-failed-retry/
3、https://www.liujiajia.me/2019/1/22/feign-retry
4、https://xiefayang.com/2019/04/26/Ribbon——超时与重试/
5、http://www.itmuch.com/spring-cloud-sum/spring-cloud-retry/
6、http://www.itmuch.com/spring-cloud-sum/spring-cloud-timeout/
记一次Ribbon重试配置不生效问题