Hystrix简介

属于一种容错机制 ,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错

1、包裹请求:使用HystrixCommand包裹对依赖的调用逻辑。自动投递微服务方法(@HystrixCommand 添加Hystrix控制) ——调⽤简历微服务
2、跳闸机制:当某服务的错误率超过⼀定的阈值时,Hystrix可以跳闸,停⽌请求 该服务⼀段时间。
3、资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(舱壁模式)(或者信号量)。如果该线程池已满, 发往该依赖的请求就被立即拒绝,而不是排队等 待,从而加速失败判定。
4、监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等
5、回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回 退逻辑由开发人员自行提供,例如返回一个缺省值。
6、我修复:断路器打开一段时间后,会自动进行“半开”状态。

雪崩场景

image.png
扇入:代表着该微服务被调用的次数,扇入大,说明该模块复用性好
扇出:该微服务调用其他微服务的个数,扇出大,说明业务逻辑复杂
扇入大是一个好事,扇出大不一定是好事

最下游简历微服务响应时间过长,大量请求阻塞,大量线程不会释放,会导致服务器资源耗尽,最终导致上游服务甚至整个系统瘫痪。

雪崩效应解决方案

应对微服务中的雪崩效应,这三种手段都是从系统可用性、可靠性⻆度出发,尽量防止系统整体缓慢甚至瘫痪

服务熔断

当扇出链路的某个微服务不可用或者响应时间太长时熔断该节点微服务的调用,进行服务的降级,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
注意:
1)服务熔断重点在“断”,切断对下游服务的调⽤
2)服务熔断和服务降级往往是一起使用的,Hystrix就是这样。

服务降级

通俗讲就是整体资源不够用了,先将一些不关紧的服务停掉(调用到的时候,再给你返回一个预留的值,也叫做兜底数据),待渡过难关高峰过去,再把那些服务打开。 服务降级一般是从整体考虑,就是当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的fallback回调,返回一个缺省值,这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强。

服务限流

服务降级是当服务出问题或者影响到核心流程的性能时,暂时将服务屏蔽掉,待高峰或者问题解决后再打开;但是有些场景并不能用服务降级来解决,比如秒杀业务 这样的核心功能,这个时候可以结合服务限流来限制这些场景的并发/请求量 限流措施也很多,比如
限制总并发数(比如数据库连接池、线程池)
限制瞬时并发数(如nginx限制瞬时并发连接数)
限制时间窗口内的平均速率(如Guava的RateLimiter、nginx的limit_req模块, 限制每秒的平均速率)
限制远程接口调用速率、
限制MQ的消费速率等

Hystrix熔断应用(调用者用)

目的:简历微服务长时间没有响应,服务消费者—>自动投递微服务快速失败给用户提示
image.png

1、消费端可以引入Hystrix依赖坐标

( 服务消费者工程(自动投递微服务) 也可以将依赖坐标添加到父文件中)

  1. <!--熔断器Hystrix-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  5. </dependency>

2、启动类中添加熔断器开启注解

入口类添加@EnableCircuitBreaker 注解

  1. @SpringBootApplication
  2. @EnableDiscoveryClient //开启服务发现
  3. //@EnableHystrix // 开启Hystrix功能
  4. @EnableCircuitBreaker // 开启熔断器功能(通用性)
  5. //@SpringCloudApplication 综合性的注解 (可以代替上面三个)
  6. //@SpringCloudApplication=@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
  7. public class AutodeliverApplication8090 {
  8. ........

3、定义熔断

扇出方法进行Hystrix控制,把当前要降级处理的方法做一个标识
定义服务降级处理方法,在业务方法上使用@HystrixCommand的 fallbackMethod属性关联到服务降级处理方法 上。熔断后返回的还是异常信息,是500,将返回信息改为兜底的显示。
原理是:会扫描有HystrixCommand此注解,此注解标识的方法就会通过面向切面方法执行

  1. /*** 提供者模拟处理超时,调用方法添加Hystrix控制 */
  2. // 使用@HystrixCommand注解进行熔断控制
  3. @HystrixCommand(
  4. // commandProperties熔断的一些细节属性配置
  5. commandProperties = {
  6. // 每一个属性都是一个HystrixProperty
  7. @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
  8. }
  9. )
  10. @GetMapping("/checkStateTimeout/{userId}")
  11. public Integer findResumeOpenStateTimeout(@PathVariable Long userId) {
  12. // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
  13. String url = "http://lagou-service-resume/resume/openstate/" + userId; // 指定服务名
  14. Integer forObject = restTemplate.getForObject(url, Integer.class);
  15. return forObject;
  16. }

4、定义服务降级

(添加一个fallbackMethod = “自定义的回退方法” // 回退方法
注意
fallbackMethod要配降级(兜底)方法,必须和被降级方法相同的方法签名(相同参数列表、相同返回值)**
可以在类上使用@DefaultProperties注解统一指定整个类中共用的降级(兜 底)方法
服务提供者端(简历微服务)模拟请求超时(线程休眠3s),只修改8080实 例,8081不修改,对比观察

/
1)服务提供者处理超时,熔断,返回错误信息
2)有可能服务提供者出现异常直接抛出异常信息
以上信息,都会返回到消费者这里,很多时候消费者服务不希望把收到异常/错误信息再抛到它的上游去
用户微服务 — 注册微服务 — 优惠券微服务
1 登记注册
2 分发优惠券(并不是核心步骤),这里如果调用优惠券微服务返回了异常信息或者是熔断后的错误信 息,这些信息如果抛给用户很不友好
* 此时,我们
可以返回一个兜底数据,预设的默认值(服务降级)**
/_
*fallbackMethod后面配置的myFallBack,是直接返回-123333的

  1. @GetMapping("/checkStateTimeoutFallback/{userId}")
  2. @HystrixCommand(
  3. // commandProperties熔断的一些细节属性配置
  4. commandProperties = {
  5. // 每一个属性都是一个HystrixProperty
  6. @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000"),
  7. },
  8. fallbackMethod = "myFallBack" // 回退方法
  9. )
  10. public Integer findResumeOpenStateTimeoutFallback(@PathVariable Long userId) {
  11. // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
  12. String url = "http://lagou-service-resume/resume/openstate/" + userId; // 指定服务名
  13. Integer forObject = restTemplate.getForObject(url, Integer.class);
  14. return forObject;
  15. }
  16. /*定义回退方法,返回预设默认值
  17. 注意:该方法形参和返回值与原始方法保持一致*/
  18. public Integer myFallBack(Long userId) {
  19. return -123333; // 兜底数据(不将异常返回前端)
  20. }

Hystrix舱壁模式(线程池隔离策略)

每个方法都分配独立的线程池,方法之间不共用线程池。
单独的为每一个控制方法创建一个线程池的方式,这种模式叫做“舱壁模式”,也是线程隔离的手段
线程池也是在HystrixCommand注解里面添加的
image.png
添加线程唯一标识:threadPoolKey
配置线程的属性: threadPoolProperties

  1. /*** 提供者模拟处理超时,调用方法添加Hystrix控制 */
  2. // 使用@HystrixCommand注解进行熔断控制
  3. @HystrixCommand(
  4. // 线程池标识,要保持唯一,不唯一的话就共用了
  5. threadPoolKey = "findResumeOpenStateTimeout",
  6. // 线程池细节属性配置
  7. threadPoolProperties = {
  8. @HystrixProperty(name="coreSize",value = "1"), // 线程数
  9. @HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
  10. },
  11. // commandProperties熔断的一些细节属性配置
  12. commandProperties = {
  13. // 每一个属性都是一个HystrixProperty
  14. @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
  15. }
  16. )
  17. @GetMapping("/checkStateTimeout/{userId}")
  18. public Integer findResumeOpenStateTimeout(@PathVariable Long userId) {
  19. // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
  20. String url = "http://lagou-service-resume/resume/openstate/" + userId; // 指定服务名
  21. Integer forObject = restTemplate.getForObject(url, Integer.class);
  22. return forObject;
  23. }

Hystrix工作流程与高级应用

image.png

1、基于springboot的健康检查观察跳闸状态(客户端微服务暴露健康检查细节)

通过访问健康检查接口详细信息:http://localhost:8090/actuator/health

  1. # springboot中暴露健康检查等断点接口
  2. management:
  3. endpoints:
  4. web:
  5. exposure:
  6. include: "*"
  7. # 暴露健康接口的细节
  8. endpoint:
  9. health:
  10. show-details: always

2、在commandProperties下添加四项时间窗口定义信息定义

  1. @GetMapping("/checkStateTimeoutFallback/{userId}")
  2. @HystrixCommand(
  3. // 线程池标识,要保持唯一,不唯一的话就共用了
  4. threadPoolKey = "findResumeOpenStateTimeoutFallback",
  5. // 线程池细节属性配置
  6. threadPoolProperties = {
  7. @HystrixProperty(name="coreSize",value = "2"), // 线程数
  8. @HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
  9. },
  10. // commandProperties熔断的一些细节属性配置
  11. commandProperties = {
  12. // 每一个属性都是一个HystrixProperty
  13. @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
  14. // hystrix高级配置,定制工作过程细节如下
  15. ,
  16. // 统计时间窗口定义
  17. @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
  18. // 统计时间窗口内的最小请求数
  19. @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
  20. // 统计时间窗口内的错误数量百分比阈值
  21. @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
  22. // 自我修复时的活动窗口长度
  23. @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")
  24. },
  25. fallbackMethod = "myFallBack" // 回退方法
  26. )
  27. public Integer findResumeOpenStateTimeoutFallback(@PathVariable Long userId) {
  28. // 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
  29. String url = "http://lagou-service-resume/resume/openstate/" + userId; // 指定服务名
  30. Integer forObject = restTemplate.getForObject(url, Integer.class);
  31. return forObject;
  32. }

Hystrix Dashboard断路监控仪表盘

工程中需要引入SpringBoot的actuator(健康监控),它提供了很多监控所需的接口,可以对应用系统进行配置查看、相关功能统计等 。、

1、可以添加到父的配置文件中

  1. <!-- Actuator可以帮助你监控和管理Spring Boot应用-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-actuator</artifactId>
  5. </dependency>

如果我们想看到Hystrix相关数据,比如有多少请求、多少成功、多少失败、多少降 级等,那么引入SpringBoot健康监控之后,访问/actuator/hystrix.stream接口可以 获取到监控的文字信息,但是不直观,所以Hystrix官方还提供了基于图形化的 DashBoard(仪表板)监控平台。Hystrix仪表板可以显示每个断路器(被 @HystrixCommand注解的方法)的状态

image.png

2、创建一个仪表盘项目并引入jar

  1. <!--hystrix-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  5. </dependency>
  6. <!--hystrix 仪表盘-->
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.cloud</groupId>
  13. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  14. </dependency>

3、启动类开启仪表盘功能

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @EnableHystrixDashboard // 开启hystrix dashboard
  4. public class HystrixDashboard9000 {
  5. public static void main(String[] args) {
  6. SpringApplication.run(HystrixDashboard9000.class,args);
  7. }
  8. }

4、添加yam.xml的配置文件

  1. server:
  2. port: 9000
  3. Spring:
  4. application:
  5. name: lagou-cloud-hystrix-dashboard
  6. eureka:
  7. client:
  8. serviceUrl: # eureka server的路径
  9. defaultZone: http://lagoucloudeurekaservera:8761/eureka/,http://lagoucloudeurekaserverb:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表
  10. instance:
  11. #使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
  12. prefer-ip-address: true
  13. #自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
  14. instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@

5、 在被监测的微服务中注册监控的servlet方法(固定的)

(自动投递微服务(被监控的客户端),监控数据就是来源于这 个微服务)看这个客户端发送信息情况

  1. /**
  2. * 在被监控的微服务中注册一个serlvet,后期我们就是通过访问这个servlet来获取该服务的Hystrix监控数据的
  3. * 前提:被监控的微服务需要引入springboot的actuator功能
  4. * @return
  5. */
  6. @Bean
  7. public ServletRegistrationBean getServlet(){
  8. HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
  9. ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
  10. registrationBean.setLoadOnStartup(1);
  11. registrationBean.addUrlMappings("/actuator/hystrix.stream");
  12. registrationBean.setName("HystrixMetricsStreamServlet");
  13. return registrationBean;
  14. }

6、访问测试http://localhost:9000/hystrix

输入监控的微服务端点地址,展示监控的详细数据,比如监控服务消费者http://locahost:8090/actuator/hystrix.stream
image.png

百分比,10s内错误请求百分比
实心圆:
大小:代表请求流量的大小,流量越大的球越大
颜色:代表请求处理的健康状态,从绿色到红色递减,绿代色表健康,红就代 表很不健康 曲
线波动图: 记录了2分钟内该方法上流量的变化波动图,判断流量上升或者下降的趋势

Hystrix Turbine聚合监控

之前是一个微服务实例的Hystrix数据查询分析,在微服务架构下,一个微服务的实例往往是多个(集群化)
如果一个微服务部署多个实例 使用Hystrix Turbine 进行聚合监控,它可以把相关微服务的监控数据聚合在一起,便于查看。
image.png

1、在pom引入坐标

  1. <!--hystrix turbine聚合监控-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
  5. </dependency>
  6. <!--
  7. 引入eureka客户端的两个原因
  8. 1、老师说过,微服务架构下的服务都尽量注册到服务中心去,便于统一管理
  9. 2、后续在当前turbine项目中我们需要配置turbine聚合的服务,比如,我们希望聚合
  10. lagou-service-autodeliver这个服务的各个实例的hystrix数据流,那随后
  11. 我们就需要在application.yml文件中配置这个服务名,那么turbine获取服务下具体实例的数据流的
  12. 时候需要ip和端口等实例信息,那么怎么根据服务名称获取到这些信息呢?
  13. 当然可以从eureka服务注册中心获取
  14. -->
  15. <dependency>
  16. <groupId>org.springframework.cloud</groupId>
  17. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  18. </dependency>

2、在工程application.yml中开启 Turbine及进行相关配置

将需要进行Hystrix监控的多个微服务配置起来,

  1. server:
  2. port: 9001
  3. Spring:
  4. application:
  5. name: lagou-cloud-hystrix-turbine
  6. eureka:
  7. client:
  8. serviceUrl: # eureka server的路径
  9. defaultZone: http://lagoucloudeurekaservera:8761/eureka/,http://lagoucloudeurekaserverb:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表
  10. instance:
  11. #使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
  12. prefer-ip-address: true
  13. #自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
  14. instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
  15. #turbine配置
  16. turbine:
  17. # appCofing配置需要聚合的服务名称,比如这里聚合自动投递微服务的hystrix监控数据
  18. # 如果要聚合多个微服务的监控数据,那么可以使用英文逗号拼接,比如 a,b,c
  19. appConfig: lagou-service-autodeliver
  20. clusterNameExpression: "'default'" # 集群默认名称

3、开启仪表盘以及Turbine聚合功能

在当前项目启动类上添加注解@EnableTurbine

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @EnableTurbine // 开启Turbine聚合功能
  4. public class HystrixTurbineApplication9001 {
  5. public static void main(String[] args) {
  6. SpringApplication.run(HystrixTurbineApplication9001.class,args);
  7. }
  8. }

4、 通过dashboard直观的查看数据

image.png

============================
image.png