1. 概述

1.1. 分布式系统需要解决的问题

复杂分布式体系结构中的应用程序有数十个依赖服务,每个依赖服务在某时将不可避免发生异常或失败。多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就叫扇出,如果扇出的链路上某个微服务的调用响应时间过长或者不可使用,对微服务A的调用就会占用越来越多的系统资源,进而引发整个系统的崩溃,称为雪崩效应,因此就需要一个组件来解决这个问题

1.2. 什么是Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个系统服务失败,避免级联故障发生,以提高分布式系统的弹性。当某个服务发生故障后,通过断路器的故障监控向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩

1.3. 重要概念

服务降级:当程序运行异常、超时、服务熔断触发、线程池/信号量打满等情况下会让客户端不再等待并返回一个友好提示
服务熔断:请求量达到最大服务访问后,直接拒绝访问,然后调用服务降级的方法并返回友好提示
服务限流:高并发操作时,严禁一瞬间过来海量请求,要求一秒钟多少个请求有序进行

2. 服务提供端集成Hystrix

2.1. 引入核心依赖

在pom.xml文件中引入Hystrix依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2.2. 业务方法配置服务降级

@HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
@GetMapping(value = "/getProviderInfoForHystrix/{message}")
public String getProviderInfoForHystrix(@PathVariable("message") String message) {try {TimeUnit.SECONDS.sleep(6);} catch (InterruptedException e) {e.printStackTrace();}return "Hello" + message + ", This is provider hystrix, The current time is " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}public String timeOutHandler(String message) {return "Hello " + message + "调用服务接口超时或异常!";
}

2.3. 主启动类引入Hystrix配置

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}
}

3. 服务消费端集成Hystrix

3.1. 引入核心依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

3.2. 配置application.yml文件

server:port: 8800
spring:application:name: cloud-hystrix
eureka:client:register-with-eureka: falsefetch-registry: trueservice-url:defaultZone: http://localhost:8761/eureka

3.3. 编写主启动类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class HystrixApplication {public static void main(String[] args) {SpringApplication.run(HystrixApplication.class, args);}
}

3.4. 编写业务接口

@RestController
@RequestMapping("/hystrix")
public class HystrixController {@Autowiredprivate ProviderClient providerClient;@GetMapping(value = "/getHystrixInfoTimeOut/{message}")@HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})public String getHystrixInfoTimeOut(@PathVariable("message") String message) {return providerClient.getProviderInfoForHystrix(message);}public String timeOutFallback(String message) {return "This is Hystrix consumer, The request Provider time out, The message is " + message;}
}

3.5. 业务类配置默认返回类

由于每个方法都配置一个异常处理类,会导致代码膨胀,可以在类上配置默认的异常处理类,在需要特殊处理的方法上再配置单独的异常处理方法

@RestController
@RequestMapping("/hystrix")
@DefaultProperties(defaultFallback = "providerDefaultFallback")
public class HystrixController {@Autowiredprivate ProviderClient providerClient;@HystrixCommand@GetMapping(value = "/getHystrixInfo/{message}")public String getHystrixInfo(@PathVariable("message") String message) {return providerClient.getProviderInfoForHystrix(message);}public String providerDefaultFallback() {return "This is Hystrix consumer The global error fallback";}
}

3.6. 编写异常请求类

上面两种方法都是在业务代码中处理异常业务,这样容易导致异常代码和业务代码混淆在一起,可以单独将异常处理拧出来,在Feign接口上引用该异常类即可

@Component
public class ProviderClientFallback implements ProviderClient {@Overridepublic String getProviderInfoForHystrix(String message) {return "failBack provider info rest service call failed!";}
}

在Feign接口上引用该异常类

@Component
@FeignClient(value = "CLOUD-PROVIDER", configuration = ProviderClientFallback.class)
public interface ProviderClient {@GetMapping(value = "/provider/getProviderInfoForHystrix/{message}")String getProviderInfoForHystrix(@PathVariable("message") String message);
}

在yml配置中开启Feign的hystrix支持

feign:hystrix:enabled: true

3.7. 编写异常回退工厂类

定义和使用一个Fallback回退处理工厂类

@Component
public class ProviderClientFallbackFactory implements FallbackFactory<ProviderClient> {@Overridepublic ProviderClient create(Throwable throwable) {return new ProviderClient() {@Overridepublic String getProviderInfoForHystrix(String message) {return "FallbackFactory fallback: provider rest service call failed!";}};}
}

在Feign接口引入该工厂类

@Component
@FeignClient(value = "CLOUD-PROVIDER", configuration = FeignConfiguration.class, fallbackFactory = ProviderClientFallbackFactory.class)
public interface ProviderClient {@GetMapping(value = "/provider/getProviderInfoForHystrix/{message}")String getProviderInfoForHystrix(@PathVariable("message") String message);
}

回退类和回退工厂类区别

  • 使用回退类时,远程调用RPC过程中所引发的异常已经被回退逻辑彻底屏蔽掉了,应用程序不方便干预,也看不到RPC过程中的具体异常
  • 使用回退工厂类时,应用程序可以通过Java代码对RPC异常进行拦截和处理

4. 服务熔断

当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制

4.1. 注解配置

在服务端新增测试熔断方法

@GetMapping(value = "/getProviderInfoForCircuitBreaker/{id}")
@HystrixCommand(fallbackMethod = "circuitBreakerFallback", commandProperties = {@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
})
public String getProviderInfoForCircuitBreaker(@PathVariable("id") Integer id) {if (id < 0) {throw new RuntimeException("id不能为负数!");}return "The id is " + id;
}public String circuitBreakerFallback(@PathVariable("id") Integer id) {return "id 不能为负数,请稍后再试! id is " + id;
}

4.2. 三个重要参数

快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近10秒
请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断,默认20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开
错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用中有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阈值情况下,这时就会将断路器打开
断路器开启或关闭的条件
当满足一定的阈值的时候(默认10秒内超过20个请求次数)
当失败率达到一定的时候(默认10秒内超过50%的请求失败)
到达以上阈值,断路器将会开启
当开启的时候,所有请求都不会进行转发
一段时间后(默认5秒),此时断路器是半开状态,会让其中一个请求进行转发,如果成功,断路器会关闭,若失败,继续开启

4.3. yml文件配置

在yml文件中也可以进行服务熔断相关配置

hystrix:command:default:circuitBreaker:enabled: true #是否开启熔断器requestVolumeThreshold: 20 #窗口时间内最小请求数sleepWindowInMilliseconds: 5000 #打开后允许一次尝试的睡眠时间,默认5秒errorThresholdPercentage: 50 #窗口时间内熔断器开启的错误比例,默认50metrics:rollingStats:timeInMilliseconds: 1000 #滑动窗口时间numBuckets: 10 #滑动窗口的时间桶数

5. RPC保护之舱壁模式

对于不同的服务提供者可以设置不同的RPC调用线程池,让不同RPC通过专门的线程池请求到各自的Provider服务提供者,像舱壁一样对Provider进行隔离,对于不同的服务提供者设置不同的RPC调用线程池,这种模式被称为舱壁模式
优点
避免对单个Provider的RPC的消耗掉所有资源,从而防止由于某一个服务性能低而引起的级联故障和雪崩效应
Hystrix提供两种RPC隔离方式:线程池隔离和信号量隔离

5.1. 线程池隔离

每一个线程池都有一个Key,名为Thread Pool Key(线程池名)。如果没有为HystrixCommand指定线程池,Hystrix就会为HystrixCommand创建一个与Group Key(命令组Key)同名的线程池,当然,如果与Group Key同名的线程池已经存在,就直接进行关联。
线程池隔离配置如下:

hystrix:threadpool:default:coreSize: 10 #线程池核心线程数maximumSize: 20 线程池最大线程数allowMaximumSizeToDivergeFromCoreSize: true #线程池maximumSize最大线程数是否生效keepAliveTimeMinutes: 10 #可空闲时间,分钟command:default:execution:isolation:strategy: THREAD #配置请求隔离方式为线程池thread:timeoutInMilliseconds: 100000 #RPC执行超时时间,默认1000毫秒interruptOnTimeout: true #超时后是否中断方法的执行,默认true

5.2. 信号量隔离

信号量所起到的作用就像一个开关,而信号量的值就是每个命令的并发执行数量,当并发数高于信号量的值时就不再执行命令。信号量可以细分为run执行信号量和fallback回退信号量
IO线程在执行HystrixCommand命令之前需要抢到run执行信号量,成功之后才允许执行HystrixCommand.run()方法。如果争抢失败,就准备回退,但是在执行HystrixCommand.getFallback()回退方法之前,还需要争抢fallback回退信号量,成功之后才允许执行HystrixCommand.getFallback()回退方法。如果都获取失败,操作就会直接终止。
信号量隔离配置如下

hystrix:command:fallback:isolation:semaphore:maxConcurrentRequests: 10 #回退信号量大小,默认为10,信号量大小不能大于容器线程池大小

5.3. 线程池隔离与信号量隔离区别

线程池隔离 信号量隔离
调用线程 RPC线程与Web容器IO线程相互隔离 RPC线程与Web容器IO线程相同
开销 存在请求排队、线程调度、线程上下文切换 无线程切换,开销低
异步 支持 不支持
并发量 最大线程池大小 最大信号量上限,且最大信号量需要小于IO线程数

6. RPC保护之熔断器模式

统计最近RPC调用发生错误的次数,然后根据统计值中的失败比例等信息决定是否允许后面的RPC调用继续,或者快速地失败回退
熔断器的3种状态如下:
关闭(closed):熔断器初始状态,RPC调用正常放行
开启(open):失败比例到一定的阈值后,熔断器进入开启状态,RPC将会快速失败,然后执行失败回退逻辑
半开启(half-open):打开一定时间后(睡眠窗口结束),熔断器进入半开启状态,小流量尝试进行RPC调用放行,如果尝试成功,熔断器就变为关闭状态,RPC调用正常,如果尝试失败,熔断器就变为开启状态,RPC调用快速失败

6.1. 熔断器配置

包含滑动窗口配置和熔断器自身配置

hystrix:command:default:circuitBreaker:enabled: true #是否开启熔断器requestVolumeThreshold: 20 #窗口时间内最小请求数sleepWindowInMilliseconds: 5000 #打开后允许一次尝试的睡眠时间,默认5秒errorThresholdPercentage: 50 #窗口时间内熔断器开启的错误比例,默认50metrics:rollingStats:timeInMilliseconds: 1000 #滑动窗口时间numBuckets: 10 #滑动窗口的时间桶数

6.2. HystrixCommand工作流程

  1. 判断是否使用缓存响应请求,若启用了缓存,且缓存可用,则直接使用缓存响应请求,Hystrix支持请求缓存,但需要用户自定义启动
  2. 判断熔断器是否开启,如果熔断器处于open状态,则跳至第5步
  3. 若使用线程池进行请求隔离,则判断线程池是否已占满,若已满则跳至第5步;若使用信号量进行请求隔离,则判断信号量是否耗尽,若耗尽则跳至第5步
  4. 使用HystrixCommand.run()方法执行具体业务逻辑,如果执行失败或者超时,就跳至第5步,否则跳至第6步
  5. 执行HystrixCommand.getFallback()服务降级处理逻辑
  6. 返回请求响应

7. 服务监控

Hystrix提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等

7.1. 引入核心依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

7.2. 编写application.yml文件

server:port: 8801
spring:application:name: cloud-hystrix-dashboard
eureka:client:register-with-eureka: falsefetch-registry: trueservice-url:defaultZone: http://localhost:8761/eureka
hystrix:dashboard:proxy-stream-allow-list: '*'

7.3. 编写主启动类

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {public static void main(String[] args) {SpringApplication.run(HystrixDashboardApplication.class, args);}
}

主要新增注解@EnableHystrixDashboard

7.4. 验证

依次启动Eureka Server、Provider和HystrixDashboard consumer微服务
浏览器地址输入http://localhost:8801/hystrix

Delay:用来控制服务器上轮询监控信息的延迟时间,默认2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗
Title:对应头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题
填写监控地址http://localhost:8770/actuator/hystrix.stream、延迟时间和应用名称

点击Monitor Stream

浏览器输入地址http://localhost:8801/hystrix/dashboard/getProviderInfoForCircuitBreaker/100,多次访问

再次在浏览器地址输入http://localhost:8801/hystrix/dashboard/getProviderInfoForCircuitBreaker/-100,多次访问

实心圆:通过颜色的变化代表了实例的健康程度,健康度从绿色<黄色<橙色<红色递减。其大小会根据实例的请求流量发生变化,流量越大该实心圆就越大
曲线:用来记录2分钟内流量的相对变化,通过其来观察到流量的上升和下降趋势

8. 聚合监控

dashboard用于监控单个微服务,如果需要监控多个微服务,就需要用到turbine

8.1. 引入核心依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>

8.2. 编写application.yml文件

server:port: 8802
spring:application:name: cloud-turbine
eureka:client:register-with-eureka: falsefetch-registry: trueservice-url:defaultZone: http://localhost:8761/eureka
hystrix:dashboard:proxy-stream-allow-list: '*'
turbine:aggregator:cluster-config: defaultapp-config: cloud-provider8771,cloud-provider8772 #服务列表cluster-name-expression: new String('default')

8.3. 编写主启动类

@EnableTurbine
@SpringBootApplication
@EnableHystrixDashboard
public class TurbineApplication {public static void main(String[] args) {SpringApplication.run(TurbineApplication.class, args);}
}

8.4. 验证

启动两个微服务,在浏览器输入地址http://localhost:8802/hystrix

多次访问两个微服务接口,在面板地址栏输入http://localhost:8802/turbine.stream,点击Monitor Stream查看监控界面信息

SpringCloud搭建微服务之Hystrix熔断器相关推荐

  1. SpringCloud入门总结 + 使用SpringCloud搭建微服务项目

    SpringCloud 1.认识微服务 2.认识spring Cloud 3.Spring Cloud Eureka 服务发现框架 3.1认识Eureka 3.2 实战--开发并部署Eureka Se ...

  2. 搭建微服务_快速搭建 SpringCloud 微服务开发环境的脚手架

    本文作者:HelloGitHub-秦人 本文适合有 SpringBoot 和 SpringCloud 基础知识的人群,跟着本文可使用和快速搭建 SpringCloud 项目. HelloGitHub ...

  3. SpringCloud + kafka + ELK 搭建微服务日志管理平台

    SpringCloud + kafka + ELK 搭建微服务日志管理平台 2019-12-31,写在前面的话 今天是2019最后一天了,最近几天都在搞这块微服务日志管理的事情,有很多种方案实现,每种 ...

  4. 【SpringCloud】微服务笔记

    写在前面 官方代码地址:https://github.com/zzyybs/atguigu_spirngcloud2020 本文地址:https://blog.csdn.net/hancoder/ar ...

  5. 九、SpringCloud基础微服务结构详解

    技术总结 架构图 一.系统架构演变 随着互联网的发展,网站应用的规模不断扩大.需求的激增,带来的是技术上的压力.系统架构也因此也不断的演进.升级.迭代.从单一应用,到垂直拆分,到分布式服务,到SOA, ...

  6. 基于SpringCloud的微服务架构演变史?

    系统架构演变概述 在公司业务初创时期,面对的主要问题是如何将一个想法变成实际的软件实现,在这个时候整个软件系统的架构并没有搞得那么复杂,为了快速迭代,整个软件系统就是由"App+后台服务&q ...

  7. 【译文】用Spring Cloud和Docker搭建微服务平台

    by Kenny Bastani Sunday, July 12, 2015 转自:http://www.kennybastani.com/2015/07/spring-cloud-docker-mi ...

  8. 用Spring Cloud和Docker搭建微服务平台

    This blog series will introduce you to some of the foundational concepts of building a microservice- ...

  9. springcloud:微服务涉及哪些技术、有哪些核心组件(二)

    0. 引言 上一期我们介绍了什么是微服务,微服务的基础概念,那么本期我们来介绍一下微服务涉及的技术点以及所需要的组件 1. 微服务涉及哪些技术 1.1.基础技术 首先每个微服务都可以看作是单机架构,所 ...

最新文章

  1. 为什么pytorch mode = sequential() 为何model(input)这样调用就直接执行了forward
  2. VULKAN学习资料收集
  3. JSP简单练习-javaBean的简单应用
  4. java sql objects_Java SQL注入学习笔记
  5. Encapsulate Collection(封装集合)
  6. Refusing to install package with name “vue-i18n“ under a package
  7. Java面向对象编程篇2——面向对象三大特点
  8. 面试 | 程序猿面试,Elasticsearch被坑被虐的体无完肤...
  9. php发送邮件时间间隔,在使用phpmailer群发邮件时如何设置发送的时间间隔?
  10. 连载:面向对象的葵花宝典:思维、技能与实践(40) - DECORATOR模式
  11. vscode安装插件提示版本不匹配或版本过低
  12. 中国信通院沈滢:字体开源协议——OFL V1.1介绍及合规要点分析
  13. 5道String面试题,能全答对的人不到10%!(附答案)
  14. Python3学习笔记十三
  15. 身高预测和体脂判断,选择结构练习,C语言
  16. 算法学习(九)之“宽度优先搜索”
  17. 治疗狗狗常见疾病药品备忘
  18. JDO示例 - JPOX
  19. power 见解_客户见解的两个简单来源,可改善用户体验
  20. SAP - 表、业务流程

热门文章

  1. 闲话计算机网络中的两军问题
  2. 山东大学软件学院项目实训第四周
  3. C语言零碎知识点之定义指针时星号靠近类型名还是变量名
  4. 1599-卡斯丁狗的炉石传说 ZCMU
  5. snowboy嵌入式_编译配置SNOWBOY
  6. python通达信5分钟转,10分钟,15分钟,30分钟,60分钟,量化交易,K线
  7. 【人脸识别】基于主成分分析PCA算法人脸识别门禁系统含Matlab源码
  8. 数学系小仙女不写代码求“破圈”,一年把华为这个社区做火了
  9. web项目web接入微信登录
  10. 泰萌主今天怎么显示服务器异常,泰萌主网络请求错误怎么办?泰萌主怎么看不了了?...