一、问题
在一次管理后台数据导入接口中,发现在大数量导入的情况下java 重试机制 关于Ribbon重试机制的坑,数据会出现重复写入的问题。后经调试发现导入接口实际上被调用了两次。初步猜测可能是Feign或的重试机制导致的。也就是管理后台服务调用业务服务,由于业务服务数据导入执行耗时较长导致超时,从而后台服务进行了重试导致。
后台服务配置如下:
<pre class="brush: html; toolbar: false">#Ribbon配置
Ribbon更新服务注册列表的频率
ribbon.ServerListRefreshInterval=2000
请求连接的超时时间
ribbon.ConnectTimeout=3000
请求处理的超时时间
ribbon.ReadTimeout=10000
复制代码</pre>
二、分析
跟踪源码,在中配置了重试相关的策略,如果.ions配置为true,则任何请求方法都进行重试,.ions配置为false时,GET请求方式也会进行重试,非GET方法只有在连接异常时才会进行重试。
<pre class="brush: html; toolbar: false">@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler (
RibbonRequest request, IClientConfig requestConfig){
// 如果OkToRetryOnAllOperations配置为true,则任何请求方法/任何异常的情况都进行重试
if (this.ribbon.isOkToRetryOnAllOperations()) {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
requestConfig);
}
// OkToRetryOnAllOperations配置为false时(默认为false)
// 非GET请求,只有连接异常时才进行重试
if (!request.toRequest().method().equals("GET")) {
return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),
requestConfig);
// GET请求任何情况/任何异常都重试
} else {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
requestConfig);
}
}
复制代码</pre>
通过上面的分析,我们可以知道并不是配置了.ions=false就不会进行重试,对于GET请求还是会进行重试的,而在我们的系统中并没有对的重试机制做特殊的配置java 重试机制,也就是用的默认值。重试机制默认配置如下:
<pre class="brush: html; toolbar: false">#同一实例最大重试次数,不包括首次调用。默认值为0
ribbon.MaxAutoRetries = 0
同一个服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
ribbon.MaxAutoRetriesNextServer = 1
是否所有操作都允许重试。默认值为false
ribbon.OkToRetryOnAllOperations = false
复制代码</pre>
由于rver配置默认值为1,而我们的导入接口恰巧又是GET请求,在业务服务接口数据处理超时的情况下,所以会自动重试一次。
三、解决方案
首先GET请求是用于数据查询类接口的请求方式,像涉及到数据插入/更新/删除等操作接口不应该用GET请求方式java 重试机制,在我们的数据导入接口中使用的是GET请求方式,所以此处是存在问题的。
像在一般的系统中,建议关闭的重试机制,如果非得开启重试,那么系统的各个接口一定要保证接口的幂等性,否则可能会导致接口逻辑被执行多次的情况,在一些重要数据的场景带来的影响将是灾难性的。
要关闭的重试将上面的rver配置为0即可,后调整的完整配置如下:
<pre class="brush: html; toolbar: false">#Ribbon配置
Ribbon更新服务注册列表的频率
ribbon.ServerListRefreshInterval=2000
请求连接的超时时间
ribbon.ConnectTimeout=3000
请求处理的超时时间
ribbon.ReadTimeout=10000
同一实例最大重试次数,不包括首次调用。默认值为0
ribbon.MaxAutoRetries = 0
同一个服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
ribbon.MaxAutoRetriesNextServer = 0
是否所有操作都允许重试。默认值为false
ribbon.OkToRetryOnAllOperations = false
复制代码</pre>
如果文章对你有帮助的话,给文章点个赞吧。
如果有写得不正确的地方,欢迎指出。