大家好,欢迎来到IT知识分享网。
feign 实现重试
我们继续使用resilience4j
实现重试,根据上一篇Spring Cloud升级之路 – Hoxton – 4. 使用Resilience4j实现实例级别的隔离与熔断,我们已经加载了RetryReqistry
这个核心配置Bean
。
Retry
相关的配置:create-and-configure-retry
我们这里的配置是:
resilience4j.retry:
configs:
default:
maxRetryAttempts: 2
waitDuration: 1
retryExceptions:
- java.lang.Exception
service-provider2:
maxRetryAttempts: 4
IT知识分享网
参考之前我们的LoadBalancerConfig
IT知识分享网//对于非返回200的接口,抛出异常
if (execute.status() != HttpStatus.OK.value()) {
throw new ResponseWrapperException(execute.toString(), execute);
}
所以,只要配置了所有异常都重试,对于非200返回也会重试。
实现重试,需要在负载均衡器作用之前,由于Spring-Cloud
中可能会有很多的胶水代码,所以利用实现FeignBlockingLoadBalancerClient
的方式可能扩展性不太好,这里使用切面的方式,实现重试。
CustomizedCircuitBreakerAspect
//配置哪些包下的FeignClient进行重试,必须含有@FeignClient注解
@Around("execution(* com.github.hashjang.hoxton..*(..)) && @within(org.springframework.cloud.openfeign.FeignClient)")
public Object feignClientWasCalled(final ProceedingJoinPoint pjp) throws Throwable {
boolean isGet = false;
MethodSignature signature = (MethodSignature) pjp.getSignature();
FeignClient annotation = signature.getMethod().getDeclaringClass().getAnnotation(FeignClient.class);
String serviceName = annotation.value();
if (StringUtils.isBlank(serviceName)) {
serviceName = annotation.name();
}
//查看是否是GET请求
RequestMapping requestMapping = signature.getMethod().getAnnotation(RequestMapping.class);
if (requestMapping != null &&
(requestMapping.method().length == 0 ||
Arrays.asList(requestMapping.method()).contains(RequestMethod.GET))
) {
isGet = true;
}
GetMapping getMapping = signature.getMethod().getAnnotation(GetMapping.class);
if (getMapping != null) {
isGet = true;
}
Retry retry;
try {
retry = retryRegistry.retry(serviceName, serviceName);
} catch (ConfigurationNotFoundException e) {
retry = retryRegistry.retry(serviceName);
}
if (!isGet) {
//非GET请求,只有在断路器打开的情况下,才会重试
retry = Retry.of(serviceName, RetryConfig.from(retry.getRetryConfig()).retryExceptions().retryOnException(throwable -> {
Throwable cause = throwable.getCause();
if (cause instanceof CallNotPermittedException) {
//对于断路器,不区分方法,都重试,因为没有实际调用
log.info("retry on circuit breaker is on: {}", cause.getMessage());
return true;
}
return false;
}).build());
}
//对于GET请求,启用重试机制
Supplier<Object> objectSupplier = Retry.decorateSupplier(retry, () -> {
try {
return pjp.proceed();
} catch (Throwable throwable) {
ReflectionUtils.rethrowRuntimeException(throwable);
return null;
}
});
return Try.ofSupplier(objectSupplier).get();
}
Spring Cloud Gateway 实现重试
Spring Cloud Gateway 默认有自己的重试,并且resilience4j
的Retry
和 Spring Cloud Gateway 的 Reactor 机制是不兼容的,所以需要写一些额外的胶水代码,这里为了简便,就使用 Spring Cloud Gateway 默认有自己的重试。利用这个重试实现重试Filter
插入到 Spring Cloud Gateway 中。
Spring Cloud Gateway 的重试Filter
通过RetryGatewayFilterFactory
实现,我们想对每个微服务调用生效,将他做成一个GlobalFilter
.并且这个重试需要在负载均衡选择实例之前,所以,这个重试,必须要在RouteToRequestUrlFilter
还有LoadBalancerClientFilter
之前(这两个负责对于lb:
路由查询负载均衡器获取实例重写 URL )。
我们想实现不同微服务不同配置,于是我们生成配置类ApiGatewayRetryConfig
:
IT知识分享网@Data
@ConfigurationProperties(prefix = "spring.cloud.gateway")
public class ApiGatewayRetryConfig {
private Map<String, RetryGatewayFilterFactory.RetryConfig> retry;
public RetryGatewayFilterFactory.RetryConfig getDefault() {
return retry.computeIfAbsent("default", key -> new RetryGatewayFilterFactory.RetryConfig());
}
}
其中的RetryConfig
包含如下我们使用到的属性:
配置项默认值说明retries3最大重试次数,不包括本身那次调用seriesSERVER_ERROR对于哪些响应码重试,默认是所有的5XX响应码statusesempty对于哪些状态码重试,这个是具体的 HttpStatus,和 series 之间只能指定一个methodsGET对于哪些 HttpMethod 重试。exceptionsList.of(IOException.class, TimeoutException.class)对于哪些异常重试,默认是IO异常和超时异常backoffbackOff配置,决定之后如何重试- firstBackoff5[ms]第一次重试间隔- maxBackoff最大重试间隔- factor2每次的重试间隔 = firstBackoff * (factor ^ (次数 – 1)),最大是maxBackoff- basedOnPreviousValuetrue是否基于上次请求的 backoff,如果是,则保留上次 backoff 时间,下次从这个 backoff 时间开始作为第一次重试间隔
我们的配置:
spring:
cloud:
gateway:
# 这是我们自定义的重试配置:ApiGatewayRetryConfig,
retry:
default:
retries: 1
series: SERVER_ERROR,CLIENT_ERROR
methods: GET
# 对于断路器打开也会重试
exceptions: io.github.resilience4j.circuitbreaker.CallNotPermittedException, org.springframework.cloud.gateway.support.TimeoutException, java.io.IOException
backoff:
basedOnPreviousValue: true
factor: 2
firstBackoff: 100ms
maxBackoff: 500ms
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/13192.html