直译是豪猪:
表达的意思就是一种保护机制,温顺平和的时候正常运行,遇到突发状况了就针锋相对,以此来保护自己。Cloud中更愿意称之为“短路器”。
设想:
微服务架构下,调用链很长,A依赖B,B依赖C,C依赖D,忽然D不可用(由于网络原因或者Exception或者机房停电),这个时候会发生连锁反应,导致ABC可能都不可用。
Hystrix帮我们解决的:
(1)熔断
在服务不可用或者多数情况下都不可用的情况下,默认该服务节点挂掉,就像保险丝一样烧断,直接返回不可用信息。免除了无意义的报错信息和等待。
(2)服务降级
在第一步熔断的基础上,为了优化用户体验,不允许直接出现500或者404之类的错误页面,而是应该执行备用计划,返回友好的提示页面或者一些缓存中的数据或者静态页面来填补页面。
(3)限流
跟地铁一样,指定时间内只允许一定的访问量,如果超过,就进行熔断和服务降级。这也是对服务端的一种保护。
网上很多很多概念,写得多高深苦涩难懂文邹邹的都有,这里我只用自己的思考去总结,用最简单的方式去搭建demo。
基础前提:
做这个demo之前必须保证已经存在服务注册中心(zookeeper/Eureka/Nacos)和服务调用(Feign/OpenFeign)和负载均衡(Ribbon)
服务降级:
1:针对生产者方的服务降级
(1)导入依赖:
<!--熔断器-->
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>RELEASE</version>
</dependency>
(2)生产方主启动类开启短路器总开关注解@EnableHystrix
(3)修改业务类,模拟调用链过长导致的响应超时场景
// 指定服务降级的处理方法,指定响应时间
@Override
@HystrixCommand(fallbackMethod = "fallback_function",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")})
public int getDemo() {
try {
// 放线程睡10秒,保证出错
TimeUnit.SECONDS.sleep(10000);
} catch (InterruptedException e) {
System.out.println("出问题了"+e);
}
return demoServiceMapper.getDemo();
}
public int fallback_function(){
System.out.println("进入出错处理方法了");
return 10086;
}
(4)两生产一消费,其中一个生产者配了熔断器,消费者发起请求:
(5)至此试验成功!
尝试下其他异常:
针对消费端的服务降级(生产端不用改,只修改消费端):
(1)主启动类:
@EnableHystrix
(2)依赖一样:
public static final String Circulate_URL = "http://CLOUD-CIRCULATE-SERVICE";
@Resource
private DemoService demoService;
@HystrixCommand(fallbackMethod = "fallback_function",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1000")})
@RequestMapping("test2")
public demo testDemo(){
return restTemplate.getForObject(Circulate_URL+"/demo/test",demo.class);
}
public demo fallback_function(){
demo demo = new demo();
demo.setName("调用出错了!测试消费端熔断成功!");
return demo;
}
测试成功!
全局服务降级:
但是每个方法都配置一个很明显不现实,所以我们可以指定一个默认的全局服务降级Service
但是至今为止,以上服务降级都是代码耦合度非常高的,不利于扩展和改造,采用一种方法可以是最少的代码修改量做到一样的事情。
做以下改造:
Controller不做任何改变
@RequestMapping("test2")
public int testDemo(){
int result = demoService.getDemo();
return result;
}
接口改成:
@Component
@FeignClient(value = "CLOUD-CIRCULATE-SERVICE", fallback = DemoServiceImpl.class)
public interface DemoService {
@RequestMapping("/demo/test")
int getDemo();
}
实现类实现这个接口,做自己的降级处理:
@Component
public class DemoServiceImpl implements DemoService{
@Override
public int getDemo() {
System.out.println("进来这里了,针对生产者的全局的服务降级");
return 3;
}
}
测试(把生产者全部停止掉):
成功~!