resilience4j-简单使用
server<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId><...
·
server
github:https://github.com/ln0491/resilience4j-springboot
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 配置
spring.application.name=eureka server
server.port=7979
eureka.instance.hostname=eureka-server
eureka.client.fetch-registry=true
eureka.client.register-with-eureka=true
- 启动
package com.ghgcn.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
provider
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- properties
spring.application.name=rj-provider
server.port=7981
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.serviceUrl.defaultZone=http://localhost:7979/eureka
#默认就是true
spring.cloud.loadbalancer.retry.enabled=true
@RestController
public class HelloContrtoller {
@GetMapping("/hello")
public String hell(String name){
String s= "hello "+name +" !";
System.out.println("s "+s+" "+new Date());
int i = 1/0;
return s;
}
}
@SpringBootApplication
public class R4jProviderApplication {
public static void main(String[] args) {
SpringApplication.run(R4jProviderApplication.class, args);
}
}
comsumer
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>0.14.1</version>
</dependency>
server.port=7877
spring.application.name=r4j-consumer
eureka.client.fetch-registry=true
eureka.client.register-with-eureka=true
eureka.client.serviceUrl.defaultZone=http://localhost:7979/eureka
resilience4j.retry.retry-aspect-order=399
resilience4j.retry.backends.retryBackendA.max-retry-attempts=3
resilience4j.retry.backends.retryBackendA.wait-duration=600
resilience4j.retry.backends.retryBackendA.event-consumer-buffer-size=1
resilience4j.retry.backends.retryBackendA.enable-exponential-backoff=true
resilience4j.retry.backends.retryBackendA.exponential-backoff-multiplier=2
resilience4j.retry.backends.retryBackendA.enable-randomized-wait=false
resilience4j.retry.backends.retryBackendA.randomized-wait-factor=2
resilience4j.retry.backends.retryBackendA.retry-exception-predicate=com.ghgcn.r4jconsumer.predicate.RecordFailurePredicate
resilience4j.retry.backends.retryBackendA.retry-exceptions=java.io.IOException,java.lang.ArithmeticException
resilience4j.retry.backends.retryBackendA.ignore-exceptions=com.ghgcn.r4jconsumer.exception.IgnoredException
- retryAspectOrder 表示 Retry 的一个优先级。默认情况下, Retry 的优先级高于 bulkhead 、 Circuit breaker 以及 rateLimiter ,即 Retry 会先于另外三个执行。 Retry、 bulkhead 、 Circuit breaker 以及 rateLimiter 的优先级数值默认分别是 Integer.MAX_VALUE-3、Integer.MAX_VALUE-2、Integer.MAX_VALUE-1 以及 Integer.MAX_VALUE ,即数值越小,优先级越高;
- backends 属性中我们可以配置不同的 Retry 策略,给不同的策略分别取一个名字, retryBackendA 就是一个 Retry 策略的名字。在 Java 代码中,我们将直接通过指定 Retry 策略的名字来使用某一种 Retry 方案;
- maxRetryAttempts 表示最大重试次数;
- waitDuration 表示下一次重试等待时间,最小为100 ms ;
- eventConsumerBufferSize 表示重试事件缓冲区大小;
- enableExponentialBackoff 表示是否开启指数退避抖动算法,当一次调用失败后,如果在相同的时间间隔内发起重试,有可能发生连续的调用失败,因此可以开启指数退避抖动算法;
- exponentialBackoffMultiplier 表示时间间隔乘数;
- enableRandomizedWait 表示下次重试的时间间隔是否随机, enableRandomizedWait 和 enableExponentialBackoff 默认为 false ,并且这两个不可以同时开启;
- retryExceptionPredicate 类似于我们上文所说的什么样的异常会被认定为请求失败,这里的RecordFailurePredicate是一个自定义的类;
- retryExceptions 表示需要重试的异常;
- ignoreExceptions 表示忽略的异常。
public class RecordFailurePredicate implements Predicate<Throwable> {
@Override
public boolean test(Throwable throwable) {
return true;
}
}
public class IgnoredException extends Exception {
}
使用
@RestController
@Retry(name = "retryBackendA")
public class HelloController {
@Autowired
RestTemplate restTemplate;
@Autowired
DiscoveryClient discoveryClient;
@GetMapping("/hello")
public String hell(String name){
List<ServiceInstance> list = discoveryClient.getInstances("rj-provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
System.err.println(host);
int port = instance.getPort();
System.err.println(port);
String serviceId = instance.getServiceId();
//String s = restTemplate.getForObject("http://" + host + ":" + port + "/hello?name={1}", String.class, name);
String s = restTemplate.getForObject("http://"+serviceId+"/hello?name={1}",String.class, name);
return s;
}
}
编程式
@RestController
public class UseHelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello2")
public String hello2(String name) {
RetryConfig config = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(5000))
.build();
Retry retry = Retry.of("id", config);
Try<String> result = Try.ofSupplier(Retry.decorateSupplier(retry, () -> helloService.hello(name)));
return result.get();
}
}
CircuitBreaker
- backendA 是断路器策略的命名,和 Retry 类似,一会也是通过注解来引用这个策略;
- ringBufferSizeInClosedState 表示断路器关闭状态下,环形缓冲区的大小;
- ringBufferSizeInHalfOpenState 表示断路器处于 HalfOpen 状态下,环形缓冲区的大小;
- waitInterval 表示断路器从 open 切换到 half closed 状态时,需要保持的时间;
- failureRateThreshold 表示故障率阈值百分比,超过这个阈值,断路器就会打开;
- eventConsumerBufferSize 表示事件缓冲区大小;
- registerHealthIndicator 表示开启健康检测。
@Service
@CircuitBreaker(name = "backendA")
public class HelloServiceCircuitBreaker {
@Autowired
RestTemplate restTemplate;
public String hello(String name) {
return restTemplate.getForObject("http://provider/hello?name={1}", String.class, name);
}
}
编程式
public String hello2(String name) {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.ringBufferSizeInHalfOpenState(20)
.ringBufferSizeInClosedState(20)
.build();
io.github.resilience4j.circuitbreaker.CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("backendA", circuitBreakerConfig);
Try<String> supplier = Try.ofSupplier(io.github.resilience4j.circuitbreaker.CircuitBreaker
.decorateSupplier(circuitBreaker,
() -> restTemplate.getForObject("http://provider/hello?name={1}", String.class, name)))
.recover(Exception.class, "有异常,访问失败!");
return supplier.get();
}
这里的 hello2 方法去访问 provider 中的接口。接口调用失败后, consumer 中自动进行服务降级,最终返回字符串为有异常,访问失败
更多推荐
已为社区贡献2条内容
所有评论(0)