目录
一、概述
在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个体系服务失败,避免级联故障,以提高分布式系统的弹性。
Hystrix 负责监控服务之间的调用情况,连续多次失败的情况进行熔断保护。保护的方法就是使用 Fallback,当调用的服务出现故障时,就可以使用 Fallback 方法的返回值;Hystrix 间隔时间会再次检查故障的服务,如果故障服务恢复,将继续使用服务。
二、应用场景
2.1 服务降级
当发生以下情况,使整体负荷超出整体负载承受能力时,保证重要或基本服务正常运行,非重要服务延迟使用或暂停使用。
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池/信号量打满
2.2 服务熔断
当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用
2.3 服务限流
在高并发系统的,网络的负载请求是有度的,可以通过对请求的并发数据进行限制来达到限流的操作。
三、配置
3.1 引入依赖
笔者尝试过不设置版本会导致依赖失败~,原因未明
<!--Hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
3.2 配置文件
#开启feign.hystrix服务降级功能
feign:
hystrix :
enabled : true
3.3 启动类
启动类上加入以下注解
@EnableHystrix
四、服务降级
4.1 controller层降级
在消费者端和服务提供端所有代码添加降级方法,无论哪里出现错误,都会进入降级方法
4.1.1 全局降级方法
在cotroller加入注解
@DefaultProperties(defaultFallback = "goodsGlobalFallbackMethod")
对需要走降级的方法加入注解
@HystrixCommand
@DefaultProperties注解为全局降级方法,对于添加**@HystrixCommand注解的方法**会走全局公共降级方法,defaultFallback属性为降级方法名称
4.1.2 指定方法降级
对需要走降级的方法加入注解
@HystrixCommand(fallbackMethod = "goodsTimeOutFallbackMethod",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
fallbackMethod为指定降级方法的方法名
commandProperties设置降级条件,以上面为例,当请求超过2000毫米时,触发降级
4.2 解耦式降级
利用feign设置fallback降级方法,只有服务端出现异常才会进入降级方法,消费端的异常会将错误抛出,并不会进入降级方法
这种方式需要额外引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
配置文件中新增
feign:
hystrix:
enabled: true
circuitbreaker:
enabled: true
为Feigin添加fallback类
@Service
@FeignClient(value = "GOODS-PROVIDER",fallback = GoodsFallbackService.class)
public interface GoodsService {
@RequestMapping("/goods/findAll")
List<GoodsBean> findAll();
@RequestMapping("/goods/buy")
GoodsBean buy(@RequestParam(value = "id") Long id, @RequestParam(value = "num") Long num);
@RequestMapping("/goods/findById")
GoodsBean findById(@RequestParam Long id);
@RequestMapping("/goods/paymentInfo_OK")
String paymentInfo_OK(@RequestParam Long id);
@RequestMapping("/goods/paymentInfo_TimeOut")
String paymentInfo_TimeOut(@RequestParam Long id);
}
此类实现本接口,每个实现方法即为调用服务的降级方法
@Component
public class GoodsFallbackService implements GoodsService {
@Override
public List<GoodsBean> findAll() {
return new ArrayList<>();
}
@Override
public GoodsBean buy(Long id, Long num) {
return null;
}
@Override
public GoodsBean findById(Long id) {
return null;
}
@Override
public String paymentInfo_OK(Long id) {
return "paymentInfo_OK的降级方法";
}
@Override
public String paymentInfo_TimeOut(Long id) {
return "paymentInfo_TimeOut的降级方法";
}
}
五、服务熔断
上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用
5.1 设置熔断属性
- circuitBreaker.enabled:是否启用熔断器,默认true
- circuitBreaker.forceOpen:强制打开熔断器,默认false。
- circuitBreaker.forceClosed:强制关闭熔断器,默认false。
- circuitBreaker.errorThresholdPercentage:错误率,默认50%。在一段时间内,服务调用超时或者失败率超过50%,则打开熔断器
- circuitBreaker.requestVolumeThreshold:默认20。意思为在一段时间内要有20个及以上的请求才会去计算错误率。比如只来了19个请求,就算全失败了,那也不算错误率100%
- circuitBreaker.sleepWindowInMilliseconds:半开状态试探睡眠时间,默认为5000ms。也就是熔断器打开5s后,开始半打开状态,放出一点请求去调用服务,试探一下能否成功
以之前做的秒杀方法为例
@Transactional
@CacheEvict(cacheNames = "goods",key = "'goods'+#id")
@HystrixCommand(fallbackMethod = "seckillCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),
})
public String buy(Long id,Long num){
GoodsBean goodsBean = goodsMapper.selectById(id);
if(goodsBean.getNum()<num){
throw new RuntimeException("库存不足");
}
goodsBean.setNum(goodsBean.getNum()-num);
goodsMapper.updateById(goodsBean);
return id.toString();
}
/**
* 秒杀熔断方法
* */
public String seckillCircuitBreaker_fallback(Long id,Long num){
return "秒杀产品失败";
}
5.2 测试
发起错误的参数,一直走服务降级方法,直到服务熔断打开,传入正确的参数请求