由于Hystrix官方已经停止更新,Spring 官网推荐使用Resilience4j作为服务的熔断保护中间件,可见Resilience4j的重要性。
为了探究Resilience4j实现服务熔断功能, 我们选用了 consul 作为注册中心,启动了一个服务端(waiter)、一个消费端(consumer)。我们关掉waiter 节点,验证 consumer 节点是否能正常熔断。 consul 启动及运行状态监控,不在这里描述, 我们默认 consul 已经正常运行。
本地安装运行consul 参考:https://jingyan.baidu.com/article/ca41422f732f961eaf99ed5f.html
2.1 pom主要依赖
1.8
Greenwich.SR1
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-consul-discovery
2.2 配置文件
application.properties
#0表示服务器随机端口
server.port=0
#consul 地址
spring.cloud.consul.host=localhost
#consul 端口
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.prefer-ip-address=true
bootstrap.properties
#服务名称
spring.application.name=waiter-service
2.3 代码配置
@PostMapping("/successKey")
@ResponseBody
public String getSuccessKey(){
return "hello wrold! you have Key !";
}
@PostMapping("/pay")
@ResponseBody
public String pay(){
return "OK! you pay success !";
}
3.1 pom主要依赖
1.8
Greenwich.SR1
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-consul-discovery
io.github.resilience4j
resilience4j-spring-boot2
0.14.1
3.2 配置文件
application.properties
server.port=8090
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
feign.client.config.default.connect-timeout=500
feign.client.config.default.read-timeout=500
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.prefer-ip-address=true
#CircuitBreaker名称为key的熔断配置
resilience4j.circuitbreaker.backends.key.failure-rate-threshold=50
resilience4j.circuitbreaker.backends.key.wait-duration-in-open-state=5000
resilience4j.circuitbreaker.backends.key.ring-buffer-size-in-closed-state=5
resilience4j.circuitbreaker.backends.key.ring-buffer-size-in-half-open-state=3
resilience4j.circuitbreaker.backends.key.event-consumer-buffer-size=10
#CircuitBreaker名称为pay的熔断配置
resilience4j.circuitbreaker.backends.pay.failure-rate-threshold=50
resilience4j.circuitbreaker.backends.pay.wait-duration-in-open-state=5000
resilience4j.circuitbreaker.backends.pay.ring-buffer-size-in-closed-state=5
resilience4j.circuitbreaker.backends.pay.ring-buffer-size-in-half-open-state=3
resilience4j.circuitbreaker.backends.pay.event-consumer-buffer-size=10
bootstrap.properties
#服务名称
spring.application.name=customer-service
3.3 代码配置
1)启动类
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
@EnableFeignClients
@EnableAspectJAutoProxy
public class CustomerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerServiceApplication.class, args);
}
@Bean
public CloseableHttpClient httpClient() {
return HttpClients.custom()
.setConnectionTimeToLive(30, TimeUnit.SECONDS)
.evictIdleConnections(30, TimeUnit.SECONDS)
.setMaxConnTotal(200)
.setMaxConnPerRoute(20)
.disableAutomaticRetries()
.setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())
.build();
}
}
2)PayService 用Feign方式调用waiter-server中的接口
@FeignClient(name = "waiter-service", contextId = "pay")
// 如果用了Fallback,不要在接口上加@RequestMapping,path可以用在这里
public interface PayService {
@PostMapping("/waiter/pay")
String pay();
@PostMapping("/waiter/successKey")
String getSuccessKey();
}
3)CustomerController http 入口
@RestController
@RequestMapping("/customer")
@Slf4j
public class CustomerController {
private CircuitBreaker circuitBreaker;
@Autowired
private PayService payService;
//熔断实现方式一(基于注册熔断器)
// CustomerController 的构造方法中注入明文“pay”的熔断器
public CustomerController(CircuitBreakerRegistry registry) {
circuitBreaker = registry.circuitBreaker("pay");
}
//熔断实现方式一(基于注册熔断器)
//当下游接口异常时候返回“CircuitBreaker effect!!”
@PostMapping("/pay" )
public Object pay(){
return Try.ofSupplier(
CircuitBreaker.decorateSupplier(circuitBreaker,
() -> payService.pay()))
.recover(CircuitBreakerOpenException.class, "CircuitBreaker effect!!")
.get();
}
//熔断实现方式一(基于注解)
//声明熔断器名称为“key”的熔断器
@GetMapping("/key")
@io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker(name = "key")
public Object getKey(){
return payService.getSuccessKey();
}
}