前言
理解断路器模式:解决了我们所编写的代码可能会失败的问题。其中很重要的一点在于,即便是失败,它也能够优雅地失败。这个强大的模式在微服务环境中会更加关键,因为在这种环境下避免跨调用堆栈产生级联失败非常重要。
相对来讲,断路器模式的理念很简单,非常类似于现实世界中的电路断路器,这也是它得名的由来。在电路断路器中,当开关处于闭合位置时,电流能够流过断路器,为房间中的电灯、电视、电脑和其他设备供电。如果线路中出现故障,比如功率骤增,断路器就会打开,在电流损坏电子设备或房屋失火之前切断电流。
与之类似,软件中的断路器起初会处于关闭状态,允许进行方法的调用。如果因为某种原因,方法调用失败了(比如时间超出了定义的阀值).断路器就会打开,就不会对失败的方法进行调用了。
如果被保护的方法在给定的失败阈值内发生了失败,那么可以调用一个后备方法代替它的位置。在断路器处于打开状态之后,几乎始终都会调用后备方法。处于打开状态的断路器偶尔会进人半开状态,并尝试调用发生失败的方法:如果依然失败,断路器就恢复为打开状态;如果调用成功,它会认为问题已经解决,断路器会回到闭合状态。
哪些方法需要添加断路器
调用REST的方法:这些方法可能会因为远程服务不可用或者返回HTTP 500响应而失败。
执行数据库查询的方法:这些方法可能会因为数据库不响应或者模式变更破坏了应用而导致失败。
可能会比较慢的方法:它们不一定会失败,但是如果耗费太长时间才能完成工作就可能会被视为失败。
声明断路器
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在主类上添加@EnableHystrix
然后为如下的方法添加一个断路器利用@HystrixCommand注解,fallbackMethod就是后备方法也就是当原方法调用失败就会调用该方法。同时所有带有@HystrixCommand注解的方法都会在1秒之后超时,并调用它们所声明的后备方法。
@RestController
public class DemoHystrix {
@GetMapping("/hystrix1")
@HystrixCommand(fallbackMethod = "backHystrix")
public int textHystrix(){
int i = 9;
//会去调用备用方法
return 9/0;
}
public int backHystrix(){
int i = 9;
return 8;
}
}
1秒超时是一个合理的默认值,适用于大多数的场景。我们也可以通过Hystrix命令属性将其调整为更大或更小的限制值。设置Hystrix 命令属性可以通过@HystrixCommand注解的commandPropertes属性来实现。commandProperties 属性是一个或多个@HystrixProperty注解所组成的数组,如下例:
@HystrixCommand(fallbackMethod="backHystrix",commandProperties={
@HystrixProperty(name="execution.isolation.thread. timeoutInMilliseconds",value="500")})
public int textHystrix(){
int i = 9;
//会去调用备用方法
return 9/0;
}
public int backHystrix(){
int i = 9;
return 8;
}
上例就是设置超时设置为0.5秒,或者,如果你认为这里不应该使用超时功能,那么我们可以将execution.timeout.enabled属性设设置为false
@HystrixProperty(name="execution.timeout.enabled",value="false")
管理断路器的阀值
默认情况下,在10秒的时间内,如果断路器保护的方法调用超过20次,而且50%以上的调用失败,那么断路器就会进人打开状态。所有后续的调用都将会由后备方法处理。在5秒之后,断路器进人半开状态,将会再次调用原始的方法。
我们可以通过设置Hystrix命令属性调整失败和重试的阈值。如下的命令属性将会影响断路器的行为
circuitBreaker.requestVolumeThreshold: 在给定的时间范围内,方法应该被调用的次数。
circuitBreak.errorThresholdPercentage:在给定的时间范围内,方法调用产生失败的百分比。
metrics.rollingStats.timeInMilliseconds:控制请求量和错误百分比的滚动时间周期。
circuitBreaker.sleepWindowInMilliseconds:处于打开状态的断路器要经过多长时间才会进入半开状态,进入半开状态之后,将会再次尝试失败的原始方法。如果在metrics.ollingState.timeInMilliseconds设定的时间范围内超出了circuitBreaker.requestVolumeThreshold和circuitBreaker.errorThresholdPercentage设置的值,那么断路器将会进人打开状态。在circuitBreaker.sleepWindowInMilliseconds限定的时间范围内,它会一直处于打开状态,在此之后将进入半开状态,进入半开状态之后,将会再次尝试失败的原始方法。
例如如下是变更设置:将其变更为在20秒的时间范围内调用超过30次且失败率超过25%
@HystrixCommand(fallbackMethod = "backHystrix",
commandProperties = {
@HystrixProperty(
//给定的时间内方法被调用的次数
name="circuitBreaker.requestVolumeThreshold",
value = "30"
),
@HystrixProperty(
//在给定的时间内,方法调用失败产生的百分比
name="circuitBreaker.errorThresholdPercentage",
value = "25"
),
@HystrixProperty(
//控制请求量和错误百分比的滚动时间
name="metrics.rollingStats.timeInMilliseconds",
value = "20000"
),
@HystrixProperty(
//处于打开状态的路由器多长时间就会在处于半开状态
name="circuitBreaker.sleepWindowInMilliseconds",
value = "60000"
),
}
)
public int textHystrix(){
int i = 9;
//会去调用备用方法
return 9/0;
}
public int backHystrix(){
int i = 9;
return 8;
}
另外,我们还设置了打开状态保持1分钟,才能进入半开状态,除了优雅地处理方法调用失败和延迟之外.Hystrix还为应用中的每个断路器提供了个指标流。 接下来, 我们看一下如何通过Hystrix流监控启用Hystrix功能的应用的生控状况。
每当断路器保护的方法被调用时,它都会收集一些调用相关的数据 ,并将其发布到一个HTTP流中,这些数据可以实时监控正在运行中的应用的健康状况。在每个断路器收集的数据中,Hystrix流包括如下内容:
■方法被调用了多少次;
■调用成功了多少次;
■后备方法调用了多少次;
■方法超时了多少次。
Hystrix流是由Actuator端点提供的。需要将Actuator依赖添加到所有服务的构建文件中,以便于启用Hystrix流即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Hystrix流端点会通过“/actuator/hystrix.stream” 路径对外暴露。默认情况下,大多数的端点都是禁用的。我们可以通过在每个应用的application.yml文件中添加如下的配置启用Hystrix端点:
management:
endpoints:
web:
exposure:
include: hystrix.stream #"*"代表开启所有的端点
actuator默认只开启health和info端点
应用启动之后,将会暴露Hystrix流(这个流可以被任意的REST端点消费)。在编写自定义的REST端点之前,我们需要注意HTTP流的每个条目都包含了各种类型的JSON数据,客户端需要大量的工作才能解析这些数据。尽管编写自定义的Hystrix流展现层并非不可能完成的任务,但是在花费大量工夫编写自己的dashboard之前我们可以考虑一下使用Hystrix的dashboard。
DashBoard监控hystrix流
此时可以重新创建一个项目然后添加也可以直接在添加了断路器的应用里添加如下,我是直接在添加了断路器的应用里添加Dashboard依赖
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
在主类上添加@EnableHystrixDashboard注解
@EnableEurekaClient
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class CloudHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(CloudHystrixApplication.class, args);
}
}
application.yml配置
server:
port: 9090
management:
endpoints:
web:
exposure:
include: hystrix.stream
启动服务后,访问http://localhost:9090/hystrix,9090是添加Dashboard依赖的端口号,之后出现如下的画面
第一个输入http://localhost:9090/hystrix/hystrix.stream,9090代表的是添加hystrix依赖(也就是添加断路器模式的应用)的端口号,因为我是放在同一个应用之中所以就都是9090。然后我们可以设置延迟和标题,延迟的默认值是2秒,指的是轮询间隔的周期,他实际上会延缓流,标题输入域的值会以标题的形式显示在监控页中。
正常情况下就会出现这样的画面
如果出现两个Loading或者直接是上面的情况说明我们是成功的,如果出现 “Unable to connect to Command Metric Stream.”
在控制台如果出现如下错误
Origin parameter: http://localhost:9090/actuator/hystrix.stream is not in the allowed list of proxy host names. If it should be allowed add it to hystrix.dashboard.proxyStreamAllowList.
在application.yml文件中添加
hystrix:
dashboard:
proxy-stream-allow-list: "localhost"
成功后调用你添加断路器模式的方法我调用了15次,然后在返回刷新你就会发现该画面发生变化如下:
然后解释一下上表中数字的含义
在图表中,折线图代表了指定方法过去两分钟的流量,简要显示了该方法的繁忙情况。
折线图的背景是一个大小和颜色会出现波动的圆圈。圆圈的大小表示当前的流量,圆圈越大,流量越大。圆圈的颜色表示它的健康状况:绿色表示健康的断路器,黄色表示偶尔发生故障的断路器,红色表示故障断路器。
以3列的形式显示各种计数器。在最左边的一列中,从上到下,第一个数字(绿色)表示当前成功调用的数量,第二个数字(蓝色)表示短路请求的数量,最后一个数字(蓝绿色)表示错误请求的数量。中间一列显示超时请求的数量(黄色)、线程池拒绝的数量(紫色)和失败请求的数量(红色)。第三列显示过去10秒内错误的百分率。
计数器下面有两个数字,代表每秒主机和集群的请求数量。这两个请求率下面是断路器的状态。监视器的底部显示了延迟的中位数和平均值,以及第90、99 和99.5百分位的延迟。
理解Hystrix的线程模型
假设某个方法要耗费大量的时间才能完成其任务。这个方法可能向其他的服务发起了HTTP请求,而该服务响应很慢。在服务响应之前,Hystrix会阻塞线程,等待响应。如果这个方法执行时与调用者在同一个线程上下文中,那么调用者将会一直在这个长时间运行的方法上进行等待。另外,如果被阻塞的线程来自一组数量有限的线程集,比如Tomcat的请求处理线程,而且这种情况一直持续 ,那么当所有线程耗尽并全部等待响应时,就会影响到可扩展性。
为了避免这种现象,Hystrix 会为每项依赖(比如带有一个或多个Hystrix命令方法的每个Spring bean)指派一个线程池。 当Hystrix 命令调用时,它将会在来自Hystrix托管的线程池的某个线程中执行,这样会将其与调用者线程隔离开。如果被调用的方法要执行较长时间,就能够允许调用线程不用一直 等待,将潜在的线程耗尽隔离在Hystrix托管的线程池中。
你可能会发现在上图中除了断路器的监视器外,在页面底部还有另一个监视器 ,位于"Theaed Pols"标题之下。这个区域是Hystrix托管的每个线程池的监视器。下图展示了一个线程池监视器,并对其中的数据进行了标注。
聚合多个Hystrix流
Hystrix dashboard一次只能监控一个流。因为每个微服务实例都发布它们自己的
Hystrix,所以几乎不可能对整个应用的健康状况历史有一个整体的 了解。
幸运的是,Netflix的另一个项目Turbine提供了将所有微服务的所有Hystrix流聚合到一个Hystrix流中的办法,这样Hystrix dashboard就能对其进行监控了。Spring Cloud Netflix.支持以类似于创建其他Spring Cloud服务的方式创建Turbine服务。要创建Turbine服务,我们需要创建一个新的 Spring Boot项目并将Turbine starter依赖添加到构建文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
在创建完新项目之后,我们需要启用Turbine 为了实现这一点, 我们需要在应用的主配置类上添加@EnableTurbine注解:
然后设置端口:
server:
port: 8989
Turine会消费多个微服务的流并将它们的断路器指标合并到一个流中。它会作为Eureka的客户端,发现那些需要聚合到自己的流的服务。但是,Turbine并不想聚合Eureka中注册的所有流,所以我们必须配置Turbine告诉它都要使用哪些服务。
turbine. app-config属性会接受个由逗号分隔的服务名称列表,Turbine中在找它们并聚合它们的Hystrix流在application.yml中设置
注意,除了turbine.app-config之外,我们还将turbine.cluster. name-expression属性设置成了" ‘default’ "。 这表明Turbine会收集名为default的集群中的所有聚合流。设置这个属性是非常重要的,否则Turbine中不会包含任何特定应用的聚合流数据。
现在,启动Turbine服务器并让Hystrix dashboard 访问http://lcalhost:8989/turbine.stream地址上的流,特定应用的所有断路器都将会展现在断路器dashboard 上.
来源:Spring实战5