服务间调用如果因为网络原因访问失败了,也可以考虑使用fegin的重发功能来重新访问服务。
配置了 ribbon或者loadBalance后,重发会根据负载均衡规则寻找新服务。
举例:feignServer客户端访问userModel服务(两个节点userModel1,userModel2)如果使用轮询策略(负载均衡)且就爱社userModel1网络中断,则feignServer访问userModel微服务,先访问userModel1发现连接失败(connect)
则重发服务再次访问userModel2,如果2也失败,会继续轮询访问userModel1。 如果userModel微服务部署的节点足够多,利用重发服务一定可以拿到响应值。
feign目前支持的重发只支持超时重发,如果要满足其他场景可以自己定义retryer重发器。
测试例子:
配置重发器 (fegin默认不使用重发机制)
两个服务节点8401服务和8404服务
其中8404服务发布的接口方法 设置线程休眠8秒钟
客户端设置超时时间来模拟fegin超时后重发服务
见如上配置可知,当客户端访问到8401端口服务,则正常访问,如果访问8404端口服务,connect连接建立之后,由于8404服务端口线程休眠了8秒钟,导致在第5秒钟时fegin就触发了超时(5秒内未拿到resonse),因此触发重发。
测试结果:第一次访问的8401端口服务,第二次访问的8404端口服务。可以看到时间开销为15秒。
为什么拿到结果的时间消耗是15秒呢? 由于我配置的connect连接超时设置是5秒,超时重发间隔是10秒,因此在请求8404服务失败后(花费5秒)。间隔10秒(花费10秒),轮询到下一个服务节点,调用服务成功,总共15秒。
由下图可得 8404服务调用了一次(超时) 8401服务调用了两次
跟踪源码
feign-core.jar.feign.SynchronousMethodHandler(类)调用invoke()方法
将代码拷出来注释
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
//获得feign服务的超时设置(见上面yml文件的配置)
Options options = findOptions(argv);
//获得配置的重发器
Retryer retryer = this.retryer.clone();
while (true) {
try {
//执行http服务 如果超时则封装一个RetryableException抛出 被下方代码捕获后进行重发
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
//判断重发次数和重发间隔
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
然后这里有个坑,如果配置了熔断方法,重发服务会失败,在超时后会进入熔断回调方法fallback,而不是进行重发。
上诉代码都是在配置中取消了熔断服务。
加上熔断服务。
调试代码:发现异常类型是HytixTimeoutException
由重发执行的代码来看,只有IOExcetion才会被捕获封装成RetryableException异常。
执行命令的线程变了
不加熔断方法(前面重发执行成功)时的线程是http-nio-8403 增加熔断方法后执行上诉访问微服务代码的线程变成了hystrix-HystrixCircuitBreakerFactory
标签:retry,服务,fegin,访问,重发,机制,超时,8404 From: https://www.cnblogs.com/UUUz/p/18249721