一、简介
Hystrix,英文意思是豪猪,全身是刺,刺是一种保护机制。Hystrix也是Netflflix公司的一款组件。
Hystrix是什么?
在分布式环境中,许多服务依赖项中的部分服务必然有概率出现失败。Hystrix是一个库,通过添加延迟和容错逻辑,来帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点阻止级联失败,通过提供回退选项来实现防止级联出错。提高了系统的整体弹性。与Ribbon并列,也几乎存在于每个Spring Cloud构建的微服务和基础设施中。
Hystrix被设计的目标是:
- 对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。
- 在复杂的分布式系统中阻止雪崩效应。
- 快速失败,快速恢复。
- 回退,尽可能优雅地降级。
二、快速开始
1、pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
2、启动类注解
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; //注解简化写法:微服务中,注解往往引入多个,简化注解可以使用组合注解。 // @SpringCloudApplication =等同于 // @SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker @SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker //开启熔断 public class DemoHystrixApplication { public static void main(String[] args) { SpringApplication.run(DemoHystrixApplication.class, args); } @Bean @LoadBalanced //开启负载均衡 public RestTemplate restTemplate() { return new RestTemplate(); } }
3、服务降级配置@HystrixCommand
使用@HystrixCommand定义fallback方法
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestHystrixController { @RequestMapping("/hystrix") @HystrixCommand(fallbackMethod = "queryByIdFallBack") public String queryById() { System.out.println("testBystrix"); return "testBystrix"; } public String queryByIdFallBack() { return "对不起,网络太过拥挤"; } }
4、配置熔断策略
- 常见熔断策略配置
- 熔断后休眠时间:sleepWindowInMilliseconds
- 熔断触发最小请求次数:requestVolumeThreshold
- 熔断触发错误比例阈值:errorThresholdPercentage
- 熔断超时时间:timeoutInMilliseconds
https://github.com/Netflix/Hystrix/wiki/Configuration#circuitBreaker.forceOpen
# 配置熔断策略: # 强制打开熔断器 默认false关闭的。测试配置是否生效 hystrix.command.default.circuitBreaker.forceOpen: false # 触发熔断错误比例阈值,默认值50% hystrix.command.default.circuitBreaker.errorThresholdPercentage: 20 # 熔断后休眠时长,默认值5秒 hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds: 60000 # 熔断触发最小请求次数,默认值是20 hystrix.command.default.circuitBreaker.requestVolumeThreshold: 5 # 熔断超时设置,默认为1秒 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 2000
5、测试
三、原理分析
熔断器的原理如同电力过载保护器。
熔断器状态机有3个状态:
- 关闭状态,所有请求正常访问
- 打开状态,所有请求都会被降级。
- Hystrix会对请求情况计数,当一定时间失败请求百分比达到阈值,则触发熔断,断路器完全关闭
- 默认失败比例的阈值是50%,请求次数最低不少于20次
- 半开状态
- 打开状态不是永久的,打开一会后会进入休眠时间(默认5秒)。休眠时间过后会进入半开状态。
- 半开状态:熔断器会判断下一次请求的返回状况,如果成功,熔断器切回关闭状态。如果失败,熔断器切回打开状态。
熔断器的核心解决方案:线程隔离和服务降级。
- 线程隔离。
- 服务降级(兜底方法)
线程隔离和服务降级之后,用户请求故障时,线程不会被阻塞,更不会无休止等待或者看到系统奔溃,至少可以看到执行结果(熔断机制)。
什么时候熔断:
- 访问超时
- 服务不可用(死了)
- 服务抛出异常(虽然有异常但还活着)
- 其他请求导致服务异常到达阈值,所有服务都会被降级
四、实际使用
**注意:**熔断服务降级方法必须保证与被降级方法相同的参数列表和返回值
两种编写方式:编写在类上,编写在方法上。在类的上边对类的所有方法都生效。在方法上,仅对当前方法有效。
方法上:服务降级的fallback兜底方法
- 使用HystrixCommon注解,定义
@HystrixCommand(fallbackMethod="queryByIdFallBack")
用来声明一个降级逻辑的fallback
兜底方法。
类上:默认服务降级的fallback兜底方法
- 刚才把fallback写在了某个业务方法上,如果方法很多,可以将FallBack配置加在类上,实现默认FallBack
@DefaultProperties(defaultFallback=”defaultFallBack“)
,在类上,指明统一的失败降级方法;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/consumer") @DefaultProperties(defaultFallback = "defaultFallback") //开启默认的 FallBack,统一失败降级方法(兜底) public class ConsumerController { @Autowired private RestTemplate restTemplate; @GetMapping("{id}") @HystrixCommand public String queryById(@PathVariable Long id) { //如果参数为1抛出异常,否则 执行REST请求返回user对象 if (id == 1) { throw new RuntimeException("too busy!!!"); } String url = String.format("http://user-service/user/%d", id); return restTemplate.getForObject(url, String.class); } /** * queryById的降级方法 */ public String queryByIdFallback(Long id) { return "对不起,网络太拥挤了!"; } /** * 默认降级方法 */ public String defaultFallback() { return "默认提示:对不起,网络太拥挤了!"; } }