Spring Boot中如何使用断路器详解

时间:2022-08-30 12:35:47

前言

随着使用 spring 进行开发的个人和企业越来越多,spring 也慢慢从一个单一简洁的小框架变成一个大而全的开源软件,spring 的边界不断的进行扩充,到了后来 spring 几乎可以做任何事情了,市面上主流的开源软件、中间件都有 spring 对应组件支持,人们在享用 spring 的这种便利之后,也遇到了一些问题。

断路器本身是电路上的一种过载保护装置,当线路中有电器发生短路时,它能够及时的切断故障电路以防止严重后果发生。通过服务熔断(也可以称为断路)、降级、限流(隔离)、异步rpc等手段控制依赖服务的延迟与失败,防止整个服务雪崩。一个断路器可以装饰并且检测了一个受保护的功能调用。根据当前的状态决定调用时被执行还是回退。通常情况下,一个断路器实现三种类型的状态:open、half-open以及closed:

  • closed状态的调用被执行,事务度量被存储,这些度量是实现一个健康策略所必备的。
  • 倘若系统健康状况变差,断路器就处在open状态。此种状态下,所有调用会被立即回退并且不会产生新的调用。open状态的目的是给服务器端回复和处理问题的时间。
  • 一旦断路器进入一个open状态,超时计时器开始计时。如果计时器超时,断路器切换到half-open状态。在half-open状态调用间歇性执行以确定问题是否已解决。如果解决,状态切换回closed状态。

Spring Boot中如何使用断路器详解

断路器背后的基本思想非常简单。将受保护的函数调用包装在断路器对象中,该对象监视故障。一旦故障达到某个阈值,断路器就会跳闸,并且所有对断路器的进一步调用都会返回错误,而根本不会进行受保护的呼叫。通常,如果断路器跳闸,您还需要某种监控器警报。

Spring Boot中如何使用断路器详解

如何快速使用hystrix呢?下面跟着我1234……

1、加入@enablecircuitbreaker注解

?
1
2
3
4
5
6
7
8
@enablecircuitbreaker
@springbootapplication
@enableeurekaclient
@enablefeignclientspublic class droolsappapplication {
 public static void main(string[] args) {
  springapplication.run(droolsappapplication.class, args);
 }
}

hystrix整体执行过程,首先,command会调用run方法,如果run方法超时或者抛出异常,且启用了降级处理,则调用getfallback方法进行降级;

Spring Boot中如何使用断路器详解

2、使用@hystrixcommand注解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@hystrixcommand(fallbackmethod = "reliable")
 public string readinglist() {
  for (int i = 0; i < 10; i++) {
   try {
    thread.sleep(1000);
   } catch (interruptedexception e) {
    e.printstacktrace();
   }
  }
  return "*mei";
 }
 
 public string reliable() {
  return "you love interesting book";
 }

3、添加引用

?
1
2
compile("org.springframework.cloud:spring-cloud-starter-hystrix")
compile('org.springframework.cloud:spring-cloud-starter-turbine')

4、设置超时时间

?
1
hystrix.command.default.execution.isolation.thread.timeoutinmilliseconds=5000

执行结果如下:

Spring Boot中如何使用断路器详解

正常应该返回:

Spring Boot中如何使用断路器详解

你不要喜欢*mei,要喜欢有意思的书;这样使用好舒服啊,@enablecircuitbreaker这个注解就这么强大吗?

hystrixcommandaspect 通过aop拦截所有的@hystrixcommand注解的方法,从而使得@hystrixcommand能够集成到spring boot中,

hystrixcommandaspect的关键代码如下:

1.方法 hystrixcommandannotationpointcut() 定义拦截注解hystrixcommand

 2.方法 hystrixcollapserannotationpointcut()定义拦截注解hystrixcollapser

 3.方法methodsannotatedwithhystrixcommand(…)通过@around(…)拦截所有hystrixcommand和hystrixcollapser注解的方法。详细见方法注解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@aspect
public class hystrixcommandaspect {
 
 private static final map<hystrixpointcuttype, metaholderfactory> meta_holder_factory_map;
 
 static {
  meta_holder_factory_map = immutablemap.<hystrixpointcuttype, metaholderfactory>builder()
    .put(hystrixpointcuttype.command, new commandmetaholderfactory())
    .put(hystrixpointcuttype.collapser, new collapsermetaholderfactory())
    .build();
 }
 
 @pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.hystrixcommand)")
 
 public void hystrixcommandannotationpointcut() {
 }
 
 @pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.hystrixcollapser)")
 public void hystrixcollapserannotationpointcut() {
 }
 
 @around("hystrixcommandannotationpointcut() || hystrixcollapserannotationpointcut()")
 public object methodsannotatedwithhystrixcommand(final proceedingjoinpoint joinpoint) throws throwable {
  method method = getmethodfromtarget(joinpoint);
  validate.notnull(method, "failed to get method from joinpoint: %s", joinpoint);
  if (method.isannotationpresent(hystrixcommand.class) && method.isannotationpresent(hystrixcollapser.class)) {
   throw new illegalstateexception("method cannot be annotated with hystrixcommand and hystrixcollapser " +
     "annotations at the same time");
  }
  metaholderfactory metaholderfactory = meta_holder_factory_map.get(hystrixpointcuttype.of(method));
  metaholder metaholder = metaholderfactory.create(joinpoint);
  hystrixinvokable invokable = hystrixcommandfactory.getinstance().create(metaholder);
  executiontype executiontype = metaholder.iscollapserannotationpresent() ?
    metaholder.getcollapserexecutiontype() : metaholder.getexecutiontype();
  object result;
  try {
   result = commandexecutor.execute(invokable, executiontype, metaholder);
  } catch (hystrixbadrequestexception e) {
   throw e.getcause();
  }
  return result;
 }

那么hystrixcommandaspect是如何初始化,是通过hystrixcircuitbreakerconfiguration实现的

?
1
2
3
4
5
6
7
@configuration
public class hystrixcircuitbreakerconfiguration {
 
@bean
public hystrixcommandaspect hystrixcommandaspect() {
return new hystrixcommandaspect();
}

那么谁来触发hystrixcircuitbreakerconfiguration执行初始化

先看spring-cloud-netflix-core**.jar包的spring.factories里有这段配置,是由注解enablecircuitbreaker触发

?
1
2
org.springframework.cloud.client.circuitbreaker.enablecircuitbreaker=\
org.springframework.cloud.netflix.hystrix.hystrixcircuitbreakerconfiguration

那么@enablecircuitbreaker如何触发hystrixcircuitbreakerconfiguration

通过源码查看,此类通过@import初始化enablecircuitbreakerimportselector类

?
1
2
3
4
5
6
7
@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@inherited
@import(enablecircuitbreakerimportselector.class)
public @interface enablecircuitbreaker {
}

enablecircuitbreakerimportselector是springfactoryimportselector子类。此类在初始化后,会执行selectimports(annotationmetadata metadata)的方法。此方法会根据注解启动的注解(这里指@enablecircuitbreaker)从spring.factories文件中获取其配置需要初始化@configuration类(这里是org.springframework.cloud.netflix.hystrix.hystrixcircuitbreakerconfiguration),从而最终初始化hystrixcommandaspect 类,从而实现拦截hystrixcommand的功能

以上就是通过@enablecircuitbreake可以开启hystrix的原理。hystrix用到了观察者模式abstractcommand.executecommandandobserve()模式,下次我们来深入说一下观察者模式。欢迎拍砖!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/viaiu/p/9534153.html