1. 什么是微服务容错
1-1) 高并发场景问题描述
- 服务提供者响应非常缓慢
- 服务消费者的请求就会被强制等待, 直到提供者响应超时
- 在高负载的场景下, 不做任何处理会导致服务消费者的资源耗尽甚至整个系统的崩溃
案例:
某电商网站在某个活动发生过载,由于过多的并发请求,导致用户的用户下单的请求延迟很久都没有响应,在等待很长时间后最终失败。许多用户又重新刷新页面并尝试再次下单,进一步增加了服务器的负载,最终整个系统都崩溃了
1-2) 雪崩效应
微服务应用架构由于各个服务之间通过网络进行通信,各个服务之间存在依赖关系,在脆弱的网络环境下,难免存在服务的级联故障
- 我们常把基础服务故障导致的级联故障的现象称为雪崩效应
1-3) 容错原理
一个基本的容错机制应该实现以下几点:
为网络请求设置超时
使用断路器模式
有点像电路的断路机制,当电流过载(功率过大/短路),需要跳闸,以保护电路的安全
-
微服务的断路器模式
正常情况下,断路器关闭
当一段时间内,请求失败率达到一定阈值(错误率百分比/每分钟次数),
断路器就会打开,不再去请求依赖的服务断路器打开一段时间后,会自动进入“半开”状态。此时,可允许一个请求访问依赖的服务,
如果调用成功,则关闭断路器;否则继续保持打开状态。
2. 使用Hystrix实现容错
2-1) Hystrix简介
Hystrix是Netflix开源的一个实现了超时机制和断路器模式的工具类库, 它支持延迟和容错库,用于隔离访问远程系统,服务或者第三方库,防止级联失败,从而提升系统的可用性和容错性。
2-2) Hystrix实现机制
- 包裹请求
使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立的线程中执行(命令模式)
- 跳闸机制
错误率/阈值 -> 停止请求服务一段时间
- 资源隔离
Hystrix为每个依赖的服务都维护了一个小型的线程池。如果该线程池已满,发往该服务的请求就会被立即拒绝,而不是排队等候,从而加速失败的判定
- 监控
Hystrix提供近乎实时的各个指标监控(成功/失败/超时/被拒绝请求)
- 回退机制
当请求失败/超时/被拒绝/断路器打开的时候,可以执行由开发人员自行定义的回退逻辑,通常就是一个缺省值
- 自我修复(Self Heal)
断路器打开一段时间后会自动进入“半开”状态
3. Hystrix实战代码
3-1)添加依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
3-2) 启动类添加注解
@EnableCircuitBreaker或@EnableHystrix
ConsumerMovieApplication.java
@EnableDiscoveryClient
@SpringBootApplication
@EnableCircuitBreaker
public class ConsumerMovieApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerMovieApplication.class, args);
}
}
3-3) 通过@HystrixCommand指定回调方法来使某个方法具备容错能力
MovieController.java
@RestController
@RequestMapping("movie")
public class MovieController {
private static final Logger LOGGER = LoggerFactory.getLogger(MovieController.class);
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@HystrixCommand(fallbackMethod = "findByIdFallback")
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
return this.restTemplate.getForObject("http://microservice-provider-user/user/" + id, User.class);
}
public User findByIdFallback(Long id) {
User user = new User();
user.setId(-1L);
user.setName("默认用户");
return user;
}
}
4. 测试
4-1) 启动eureka
4-2) 启动microservice-provider-user
4-3) 启动microservice-consumer-movie-ribbon-hystrix
4-4) 停止microservice-provider-user
本文的github代码地址:
https://github.com/davidgjy/springcloud-learn/tree/master/3_hystrix