Hystrix熔断器
概述
分布式系统面临的问题
- 复杂分布式体系结构中的应用程序 有数10个依赖关系,每个依赖关系在某些时候将不可避免地失败。
- 假设一个服务需要走ABCD是个服务,如果D服务出现问题会导致服务雪崩的问题
服务雪崩
扇出:多个服务之间调用的时候,假设微服务A调用微服务B和微服务C的时候,微服务B和微服务C又调用其他的微服务。
雪崩:一个模块下的某个实例失败后,这时候这个模块依然还会接收请求,这个有问题的模块还会调用其他的模块,这就会发生级联故障。
如果扇出的链路扇某个微服务调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓雪崩效应。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还会导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致系统发生更多的级联故障。
这些问题表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能影响整个应用程序或系统。
Hystrix 是什么
- 官网资料:GitHub - Netflix/Hystrix
- 一个用于处理分布式系统的延迟和容错的开源库。Hystrix能够保证在系统出现问题(比如超时,异常等)的情况下,不会发生整体服务失败,避免级联故障,进而提高分布式系统的弹性。
- “断路器”本身是一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控(类似熔断保险丝),向调用者返回一个符合预期、可处理的备选响应(FallBack) ,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
- Hystrix 提供了以下功能
- 服务降级
- 服务熔断
- 接近实时的监控
已停更😒
官宣:停更进维,不在接受合并请求,不再发布新版本,被动修复bug
推荐新项目使用 resilience4j (github.com),国外使用的多,国内使用阿里出的Sentinel。
重要概念
服务降级
- 降级就是为了解决资源不足和访问量增加的矛盾
- 比如服务器忙,调用后立刻返回友好的提示
- 需要发生降级的情况
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池/信号量也会导致服务降级
服务熔断
- 在分布式系统中,我们往往需要依赖下游服务,不管是内部系统还是第三方服务,如果下游出现问题,我们还是盲目地去请求,如果失败了多次,还是傻傻的去请求,去等待。一是增加了整个链路的请求时间,第二,下游系统本身就出现了问题,不断的请求又把系统问题加重了,恢复困难。
- 熔断模式可以防止应用程序不断地尝试可能超时和失败的服务,能达到应用程序执行而不必等待下游服务修正错误服务。
- 类比保险丝达到了最大的服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好的提示。
服务限流
- 通过对并发访问进行限速,从进入的流量上进行限制,达到保护系统的作用;
构建8001服务
新建 Module,cloud-provider-hystrix-payment8001, 加入hystrix的依赖
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<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>配置文件 application.yml
1
2
3
4
5
6
7
8
9
10
11server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka启动类
1
2
3
4
5
6
7
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
业务类
service:提供超时和正常访问的方法
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
public class PaymentService {
/**
* 正常访问
*
* @param id
* @return
*/
public String paymentInfo_OK(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK,id:" + id + "\t" + "O(∩_∩)O哈哈~";
}
/**
* 超时访问
*
* @param id
* @return
*/
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 3;
try {
// 暂停3秒钟
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
"O(∩_∩)O哈哈~ 耗时(秒)" + timeNumber;
}
}controller: 提供正常访问和超时的接口
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
public class PaymentController {
private PaymentService paymentService;
private String servicePort;
/**
* 正常访问
*
* @param id
* @return
*/
public String paymentInfo_OK( { Integer id)
String result = paymentService.paymentInfo_OK(id);
log.info("*****result:" + result);
return result;
}
/**
* 超时访问
*
* @param id
* @return
*/
public String paymentInfo_TimeOut( { Integer id)
String result = paymentService.paymentInfo_TimeOut(id);
log.info("*****result:" + result);
return result;
}
}
正常测试
- 先启动eureka服务,后启动 hystrix服务
- 访问超时和正常访问的接口,超时接口花费4秒左右
高并发测试8001
上述在非高并发的情况下还勉强能满足, ok接口7ms
使用 Jmeter压测测试, 使用2000个并发访问timeout接口后,再次访问
可以看到耗时变长了,20000个线程访问的是timeout接口,tomcat的默认工作线程数被打满了,没有多余的线程来分解压力和处理
构建80微服务
创建cloud-comsumer-feign-hystrix-order80模块
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
43<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>pers.fulsun.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>application.yml 配置文件
1
2
3
4
5
6
7
8server:
port: 80
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka主启动类
1
2
3
4
5
6
7
8
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
业务类
通过feign调用8001微服务的正常和超时接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface PaymentHystrixService {
/**
* 正常访问
*
* @param id
* @return
*/
String paymentInfo_OK(; Integer id)
/**
* 超时访问
*
* @param id
* @return
*/
String paymentInfo_TimeOut(; Integer id)
}controller提供访问接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class OrderController {
private PaymentHystrixService paymentHystrixService;
public String test() {
return "test";
}
public String paymentInfo_OK({ Integer id)
String res = paymentHystrixService.paymentInfo_OK(id);
System.out.println(res);
return res;
};
public String paymentInfo_ERROR({ Integer id)
return paymentHystrixService.paymentInfo_TimeOut(id);
}
}
正常测试
- 启动80微服务,访问 http://localhost/info/ok/2 , 能够正常访问,速度很快。
高并发测试
使用jmeter,用30000个线程访问8001微服务
使用80微服务调用8001的OK服务 http://localhost/info/ok/2
可以看到有二种情况
一种是在转圈,比较慢
出现error页面,报超时错误
故障现象
- 8001同一层次的其他接口被困死,因为tomcat线程池里面的工作线程已经被挤占完毕
- 80此时调用8001,客户端访问响应缓慢,转圈圈
问题解决
思路
- 超时导致服务器变慢(转圈) , 超时不再等待
- 出错(宕机或程序运行出错),出错要有兜底
解决
- 对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级
- 对方服务(8001)down了,调用者(80)不能一直卡死等待,必须有服务降级
- 对方服务(8001)OK,调用者(80)自己有故障或自己的超时等待时间小于服务提供者
8001服务降级
- 设置服务提供者(8001)自身调用超时时间的峰值,在峰值内可以正常运行,超过了需要有兜底的方法处理进行服务降级(fallback)
启用Hystrix
在主启动类上添加
@EnableCircuitBreaker
, 也可使用@EnableHystrix
,EnableHystrix中包含了EnableCircuitBreaker注解1
2
3
4
5
6
7
8
//激活hystrix
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
超时启用降级
使用
使用@HystrixCommand(fallbackMethod = “getFallback”)
,fallbackMethod 是降级服务时使用的方法,这个方法需要返回值一样,参数一样
设置接收3秒钟,方法运行超过3秒钟,出现超时异常走fallback指定的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 4;
try {
// 暂停3秒钟
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\t" +
"O(∩_∩)O哈哈~ 耗时(秒)" + timeNumber;
}
public String getPaymentInfo_TimeOutHandler(Integer id) {
return Thread.currentThread().getName()+"-----------paymentInfo_TimeOut, 请稍后重试。--------"+id;
}重新启动8001服务后访问 http://localhost:8001/payment/hystrix/timeout/1 ,可以看到3s后就有返回结果。
80服务降级
80订单微服务,也可以更好的保护自己,进行客户端端降级保护
我们自己配置过的热部署方式对java代码的改动明显,但对
@HystrixCommand
内属性的修改建议重启微服务
项目准备
加入Hystrix的依赖
1
2
3
4
5<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>yaml配置
1
2
3
4
5
6
7
8server:
port: 80
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka主启动类添加
@EnableHystrix
1
2
3
4
5
6
7
8
9
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
超时服务降级
设置超时时间,调用者(80)不能一直卡死等待
1
2
3
4
5
6
7
8
9
10
11
12
public String paymentInfo_ERROR( { Integer id)
//int age = 10/0;
return paymentHystrixService.paymentInfo_TimeOut(id);
}
public String paymentTimeOutFallbackMethod( { Integer id)
return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
服务down降级
可以自己测试异常导致的服务降级
先启动eurek,然后启动8001微服务,80微服务,然后正常访问后,关闭8001微服务,再次用80调用者访问
此时服务端8001已经downl ,但是我们做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器
优化
- 配置了服务降级后,可以避免了错误故障,通过上面的写法,我们发现我们需要对每一个业务方法配置一个fallbakc方法,随着业务的接口增加,兜底方法也会增加,出现代码膨胀。
解决代码膨胀
(×)为每个方法1:1配置服务降级方法
(√)除了个别重要和兴业务外,其他方法通过全局的fallback方法统一处理
@DefaultProperties(defaultFallback="")
指定全局的降级方法,如果@HystrixCommand
没有指定fallbackMethod就走统一的方法。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@RestController
@DefaultProperties(defaultFallback = "globalFallbackMethod")
public class OrderController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("info/timeout/{id}")
- @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
- @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
- })
+ @HystrixCommand
public String paymentInfo_ERROR(@PathVariable("id") Integer id) {
//int age = 10/0;
return paymentHystrixService.paymentInfo_TimeOut(id);
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
+ public String globalFallbackMethod() {
+ return "Global异常处理信息,请稍后重试.o(╥﹏╥)o";
+ }
}
业务代码分离
上面的写法虽然减少了代码的膨胀,但是降级方法和业务逻辑写在一起。
80调用者controller层调用的service接口,用了@FeignClient注解,FeignClient是服务调用,把客户端与服务器端注入eureka,来调用我们的服务器端的接口,fallback的是继承HystrixService 类为其设计的fallback处理逻辑,我们只需要为Feign客户端定义的接口,添加一个服务降级处理的实现类即可实现解耦。
1
2
3
4
5
6
7
8
9
10
11
12//将fallback接口添加到容器中
public class PaymentFallbackHystrixService implements PaymentHystrixService {
public String paymentInfo_OK(Integer id) {
return "-------PaymentFallbackService fall back-paymentInfo_OK,o(╥﹏╥)o";
}
public String paymentInfo_TimeOut(Integer id) {
return "-------PaymentFallbackService fall back-paymentInfo_TimeOut,o(╥﹏╥)o";
}
}在feign中指定fallback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23@Component
- @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
+ @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackHystrixService.class)
public interface PaymentHystrixService {
/**
* 正常访问
*
* @param id
* @return
*/
@GetMapping("/payment/hystrix/ok/{id}")
String paymentInfo_OK(@PathVariable("id") Integer id);
/**
* 超时访问
*
* @param id
* @return
*/
@GetMapping("/payment/hystrix/timeout/{id}")
String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}配置yaml
1
2
3
4# 用于服务降级,在@FeignClient注解中加入fallback属性值
feign:
hystrix:
enabled: true
服务降级优先级
- 通过上面的示例,可以知道有3种方式配置服务降级方法,fallback的位置定义如下
- 控制类HystirxController上DefaultProperties注解默认fallback
- 控制层执行方法SingleHystirxController上HystrixCommand注解单独设置的fallback
- 调用service方法@FeignClient(fallback = FallbackService .class)
- 如果都定义了,fallback优先显示:3>2>1
服务熔断
熔断机制
- 熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
- 当检测到该节点微服务调用响应正常后,恢复调用链路。
- 在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定间值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand。
- 参考 https://martinfowler.com/bliki/CircuitBreaker.html
- 翻译:【译文】熔断器-CircuitBreaker)
实操
Circuit Breaker
对8001微服务的service设置短路器
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
33package pers.fulsun.sc.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class PaymentService {
//---服务的熔断
public String paymentCircuitBreaker( { Integer id)
if (id < 0) {
throw new RuntimeException("******id不能为负数");
}
String simpleUUID = UUID.randomUUID().toString().replace("-", "");
return Thread.currentThread().getName() + "\t" + "成功调用,流水号是:" + simpleUUID;
}
public String paymentCircuitBreaker_fallback( { Integer id)
return "id不能为负数,请稍后再试............" + id;
}
}controller提供接口
1
2
3
4
5//circuit 电路
public String paymentCircuitBreaker({ Integer id)
String res = paymentService.paymentCircuitBreaker(id);
return res;
}测试,多次访问异常接口 http://localhost:8001/info/circuit/-11 , 然后访问正常的接口,发现就算是正确的访问也不能进行了
熔断原理
This simple circuit breaker avoids making the protected call when the circuit is open,but would need an external intervention to reset it when things are well again. This is a reasonable approach with electrical circuit breakers in buildings, but for software circuit breakers we can have the breaker itself detect if the underlying calls are working again. We can implement this self-resetting behavior by trying the protected
call again after a suitable interval, and resetting the breaker should it succeed.这种简单的熔断器避免在电路打开时发出受保护的调用,但在事情再次良好时需要外部干预来重置它。这是一个合理的方法,用于建筑物中的电气熔断器,但对于软件熔断器,我们可以让熔断器自己检测底层调用是否再次工作。我们可以通过在适当的间隔后再次尝试受保护的调用来实现这种自我重置行为,如果它成功的话,重新设置熔断器。
熔断打开:请求不再调用当前服务,内部设置一般为MTTR(平均故障处理时间),当打开长达导所设时钟则进入半熔断状态
熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断
熔断关闭:熔断关闭后不会对服务进行熔断
流程图
熔断器逻辑
- 假设电路的音量达到一定阈值 ()…
HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()
- 假设错误百分比超过阈值错误百分比 ()…
HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()
- 然后断路器从
CLOSED
过渡到OPEN
。 - 当断路器是OPEN的,会短路对该断路器进行的所有请求。
- 经过一段时间后(
HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()
),下一个请求是允许通过(HALF-OPEN
)。如果请求失败,断路器在睡眠窗口期间返回OPEN
状态。如果请求成功,断路器将转换为CLOSED
.逻辑1再次接管。
开启断路器条件
涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。
- 快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
- 请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,
即使所有的请求都超时或其他原因失败,断路器都不会打开。 - 错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过
50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。
到达以下阈值,断路器将会开启,所有请求不会转发。
- 当满足一定的阈值的时候(默认10秒钟超过20个请求次数)
- 当失败率达到一定的时候(默认10秒内超过50%的请求次数)
一段时间之后(默认5秒),这个时候断路器是半开状态,会让其他一个请求进行转发.如果成功,断路器会关闭,若失败,继续开启.重复4和5操作。
详细配置
断路器配置
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public String strConsumer() {
return "hello word";
}
public String str_fallbackMethod()
{
return "fall back str_fallbackMethod";
}
监控调用
- 除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard), Hystrix会持续地记录所有通过Hystrix发
起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。 - Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成
可视化界面。
新建hystrix-dashboard
新建module: cloud-consumer-hystrix-dashboard9001
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<dependencies>
<!--hystrix dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--热部署-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-devtools</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->
</dependencies>配置端口
1
2server:
port: 9001启动类添加注解
@EnableHystrixDashboard
1
2
3
4
5
6
7
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class);
}
}监控
所有Provider微服务提供类都需要添加监控依赖
1
2
3
4
5<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>启动9001项目,访问 http://localhost:9001/hystrix
监控8001
注意:SpringCloud2.0版本,不再默认支持hystrix.stream路径输出,需要在主启动MainAppHystrix8001中指定监控路径,
这里我们监控8001,在8001的主启动进行配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//激活hystrix
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);
}
/**
* 此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
* ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
* 只要在自己的项目里配置下面的Servlet就可以了
* @return
*/
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}重启8001后,在9001监控服务输入监控地址 http://localhost:8001/hystrix.stream 到此单个应用的熔断监控已经完成。
第一次访问是没有数据的,可以访问带有
@HystrixCommand
注解的接口 http://localhost:8001/info/circuit/11 , http://localhost:8001/info/circuit/-11 来测试
怎么看
7色
实心圆
- 实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
- 它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。
- 所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
曲线:
- 用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。
断路器的监视器
整体解释
1
2
3
4
5
6
7
8
9
10
11
12
13折线图代表了指定方法过去两分钟的流量,简要显示了改方法的繁忙情况。
折线图的背景是一个大小和颜色会出现波动的圆圈,圆圈的大小表示当前的流量,圆圈越大,流量越大。圆圈的颜色表示它的建库状况:绿色表示建库的断路器,黄色表示偶尔发生故障的断路器,红色表示故障断路器。
在监视器的右上角,以3列的形式显示各种计数器。在最左边的一列中,从上到下
第一个数字(绿色)表示当前成功调用的数量;
第二个数字(蓝色)表示短路请求的数量;
最后一个数字(蓝绿色)表示错误请求的数量。
中间一列显示超时请求的数量(黄色)、
线程池拒绝的数量(紫色)
失败请求的数量(红色)。
第三列显示过去10s内错误的百分率。
计数器下面有两个数字,代表每秒主机和集群的请求数量。
这两个请求率下面是断路器的状态。
Median和Mean显示了延迟的中位数和平均值。90th、99th、99.5表示百分位的延迟。
线程池的监视器说明
与断路器的监视器类似,每个线程池监视器在左上角都包含一个圆圈,圆圈大小和颜色代表了线程池的活跃状态以及健康状况。与断路器的监视器不同的是,线程池的监视器没有显示过去几分钟线程池活跃的折线图。
右上角显示线程池的名称,其下方是线程池中线程每秒处理请求的数量。
线程池监视器的左下角显示如下信息
- 活跃线程:当前活跃线程的数量
- 排队线程:当前有多少线程在排队。默认情况下,队列功能是禁用的,所以这个值始终为0.
- 线程池的大小:线程池中有多少线程
右下角显示如下信息
- 最大活跃线程:在当前的采样周期中,活跃线程的最大数量
- 执行次数:线程池中的线程被调用执行Hystrix命令的次数
- 线程队列大小:线程池队列的大小。线程队列功能默认是禁用的,所以这个值没有什么意义
Turbine
- 在复杂的分布式系统中,相同服务的节点经常需要部署上百甚至上千个,很多时候,运维人员希望能够把相同服务的节点状态以一个整体集群的形式展现出来,这样可以更好的把握整个系统的状态。 为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。
构建项目
pom.xml
1
2
3
4
5
6<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
</dependencies>配置文件
turbine.appConfig :配置Eureka中的serviceId列表,表明监控哪些服务
turbine.aggregator.clusterConfig :指定聚合哪些集群,多个使用”,”分割,默认为default。可使用
http://ip:port/turbine.stream?cluster={clusterConfig之一}
访问turbine.clusterNameExpression : 指定集群名称
默认表达式appName;此时turbine.aggregator.clusterConfig需要配置想要监控的应用名称;
当clusterNameExpression: default时,turbine.aggregator.clusterConfig可以不写,因为默认就是default;
当clusterNameExpression: metadata[‘cluster’]时,假设想要监控的应用配置了eureka.instance.metadata-map.cluster: ABC,则需要配置,同时turbine.aggregator.clusterConfig: ABC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19server:
port: 9002
spring:
application:
name: hystrix-dashboard-turbine
eureka:
instance:
hostname: localhost
prefer-ip-address: true #注册时使用ip而不是主机名
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://127.0.0.1:7001/eureka
turbine:
app-config: cloud-provider-hystrix-payment,cloud-comsumer-order
cluster-name-expression: new String("default")
combine-host-port: true
instanceUrlSuffix: /hystrix.stream
启动类添加@EnableTurbine,激活对Turbine的支持
1
2
3
4
5
6
7
8
public class TerbineMain9002 {
public static void main(String[] args) {
SpringApplication.run(TerbineMain9002.class);
}
}到此Turbine(hystrix-dashboard-turbine)配置完成
测试
我们配置文件指定了了cloud-provider-hystrix-payment,cloud-comsumer-order二个微服务,启动后,访问带有Hystrix注解的接口,
访问:http://localhost:8001/payment/hystrix/timeout/1 http://localhost/info/ok/1
查看流信息 http://localhost:9002/turbine.stream ,会不断刷新以获取实时的监控数据,说明和单个的监控类似,返回监控项目的信息
1
2: ping
data: {"reportingHostsLast10Seconds":1,"name":"meta","type":"meta","timestamp":1635077637139}访问 hystrix的监控页 http://localhost:9001/hystrix/monitor?stream=http://localhost:9002/turbine.stream , 可以看到出现了多个监控列表,尝试访问不同的接口