服务断路器简介
断路器(CircuitBreaker)一共有六种状态,CircuitBreaker常用的三种状态(CLOSED、OPEN、HALF_OPEN)
断路器默认是CLOSE关闭状态
- closed -> open,关闭状态到熔断状态,当失败调用率的阈值达到50%时会开启断路器
- open -> half_open,从熔断状态到半开状态,CircuitBreaker默认60s允许服务调用者将一部分请求发到服务提供者
- half_open -> open,当half_open的调用失败率超过给定的阈值,转为open状态
- open -> closed,调用失败率低于给定的阈值,打开CircuitBreaker
Resilience4j实现服务降级
在完成这个案例时,要先明白什么时候会出现服务降级
出现服务降级的情况
- 程序运行时异常
- 超时
- 熔断
- 线程池/信号量打满
这个案例使用超时来实现服务降级的操作
pom.xml
消费者引入Resilience4j依赖
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-cloud2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
生产者
创建一个超时方法
// 超时方法
@GetMapping("/timeout")
public String timeout(){
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "payment successful timeout";
}
消费者
yml文件
server:
port: 80
eureka:
instance:
instance-id: customer-resilience4j-order80
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
spring:
application:
name: customer-openfeign-order
# 配置resilience4j超时时间,默认超时时间是5s,当出现超时会触发服务降级
resilience4j:
timelimiter:
instances:
delay:
timeoutDuration: 2
使用openfeign进行远程调用
@FeignClient(value = "服务生产者应用名")
public interface OpenFeignMapper {
@GetMapping("/payment/timeout")
String timeout();
}
主启动类
@EnableFeignClients
@SpringBootApplication
@Slf4j
public class OrderResilience4j80 {
public static void main(String[] args) {
SpringApplication.run(OrderResilience4j80.class,args);
log.info("************ OrderResilience4j80 successful ***************");
}
}
控制层
使用的是Resilience4j,需要遵循规定的编写风格,方法的返回值需要时异步的,需要自己构建带有返回值的异步任务
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/timeout")
@TimeLimiter(name="delay",fallbackMethod = "fallback")
public CompletableFuture<String> timeout(){
CompletableFuture<String> stringCompletableFuture = CompletableFuture
.supplyAsync((Supplier<String>) () -> orderService.timeout());
return stringCompletableFuture;
}
public CompletableFuture<String> fallback(Exception e){
e.printStackTrace();
return CompletableFuture.completedFuture("超时啦");
}
}