源码: https://gitee.com/GXQ205153964/Hystrix-parent.git

预防雪崩
问题:
这里有一个线程池对应3个服务,当哪个服务被调用时,线程池会分配一个线程运行。当C发生故障后线程池的线程依旧会执行C服务,从而导致线程池线程用完,从而导致BD服务也无法使用。

解决:
线程池隔离:把A分成3个线程池分别对应三个服务,C坏了后,BD不会收到影响。

信号量隔离:对BCD加一个阀门,只允许一定的数量的人经行访问,超过就不能访问了,从而阻止C将所有的线程池资源耗尽。




(c降级方案)
流程:
基础代码构建
SpringCloud EurekeServer Consumer和provider

provider:
pom.xml
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
- dependency>
ProviderApp启动类(开启熔断器)
- //启动类
- @EnableEurekaClient
- @SpringBootApplication
- @EnableCircuitBreaker//开启Hystrix熔断器
- public class ProviderApp {
- public static void main(String[] args){
- SpringApplication.run(ProviderApp.class,args);
- }
- }
GoodsController
- package com.gao.controller;
-
- import com.gao.domain.Goods;
- import com.gao.service.GoodsService;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
-
- //服务提供方
- @RestController
- @RequestMapping("/goods")
- public class GoodsController {
- @Autowired
- private GoodsService goodsService;
-
- /**/
- //这里注入port可时刻监控哪个服务被调用
- @Value("${server.port}")
- private int port;
- /**
- *降级:
- * 出现异常
- * 服务调用超时
- */
- @GetMapping("/findOne/{id}")
- //指定降级后调用的方法
- @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties ={
- //修改几秒后超时
- @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
- })
- public Goods findOne(@PathVariable("id") int id){
- Goods goods = goodsService.findOne(id);
- //造个异常
- //int i =3/0;
- //超时
- try{
- //休眠两秒
- Thread.sleep(2000);
- }catch (InterruptedException e){
- e.printStackTrace();
- }
- //将端口号,设置到了商品标题上方便监控
- goods.setTitle(goods.getTitle()+" "+"port" + ":" + port);
-
- return goods;
- }
- /**
- * 定义降级方法
- *方法的返回值需要和原方法一样
- * 方法的参数需要和原方法一样
- */
- public Goods findOne_fallback(int id){
- Goods goods = new Goods();
- goods.setTitle("降级了~~~");
- return goods;
- }
- }

consumer使用了feign,而feign里已经集成了Hystrix,不用再引入feign依赖了

开启feign对hystrix的支持
- #开启feign对hystrix的支持
- feign:
- hystrix:
- enabled: true
pom.xml
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
-
- dependencies>
GoodsFeignClient
- package com.gao.feign;
-
- @FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
- public interface GoodsFeignClient {
- @GetMapping("/goods/findOne/{id}")
- public Goods findGoodById(@PathVariable("id") int id);
- }
GoodsFeignClientFallback
- package com.gao.feign;
-
- @Component
- public class GoodsFeignClientFallback implements GoodsFeignClient {
-
- @Override
- public Goods findGoodById(int id) {
- Goods goods = new Goods();
- goods.setTitle("又被降级了~~~");
- return goods;
- }
- }
启动类上加
@EnableFeignClients//启动feign
测试结果

当服务C坏掉后,启动了降级方案,返回给A是好的值,所以A不会启动降级方案。在A和C之间不能通信时(例如断网,或者直接关掉C),A会启动降级方案

在provider里的GoodsController里添加
- 当id=1时,出现异常id=2时正常
- //熔断
- //如果id==1,则出现异常,id !=1 则正常访问
- if(id == 1){
- //造个异常
- int i =3/0;
- }
启动ProviderApp,5秒失败20次,刷新,当达到这个情况下,当id变为2时也会降级。说明启动了熔断,等五秒后会自动启动,id=2时又可以用了。
- package com.gao.controller;
-
- import com.gao.domain.Goods;
- import com.gao.service.GoodsService;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
-
- //服务提供方
- @RestController
- @RequestMapping("/goods")
- public class GoodsController {
- @Autowired
- private GoodsService goodsService;
-
- /**/
- //这里注入port可时刻监控哪个服务被调用
- @Value("${server.port}")
- private int port;
- /**
- *降级:
- * 出现异常
- * 服务调用超时
- */
- @GetMapping("/findOne/{id}")
- //指定降级后调用的方法
- @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties ={
- //修改几秒后超时
- @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000"),
- //监控时间 默认5000 毫秒
- @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
- //失败次数。默认20次
- @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
- //失败率 默认50%
- @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
- })
- public Goods findOne(@PathVariable("id") int id){
- Goods goods = goodsService.findOne(id);
-
- //熔断
- //如果id==1,则出现异常,id !=1 则正常访问
- if(id == 1){
- //造个异常
- int i =3/0;
- }
-
- //降级
- //造个异常
- int i =3/0;
- //超时
- /*
- try{
- //休眠两秒
- Thread.sleep(2000);
- }catch (InterruptedException e){
- e.printStackTrace();
- }
- */
-
- //将端口号,设置到了商品标题上方便监控
- goods.setTitle(goods.getTitle()+" "+"port" + ":" + port);
-
- return goods;
- }
- /**
- * 定义降级方法
- *方法的返回值需要和原方法一样
- * 方法的参数需要和原方法一样
- */
- public Goods findOne_fallback(int id){
- Goods goods = new Goods();
- goods.setTitle("降级了~~~");
- return goods;
- }
- }
修改熔断基础属性
//监控时间 默认5000 毫秒 @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"), //失败次数。默认20次 @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"), //失败率 默认50% @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
provider GoodsController
- package com.gao.controller;
-
- //服务提供方
- @RestController
- @RequestMapping("/goods")
- public class GoodsController {
- @Autowired
- private GoodsService goodsService;
-
- /**/
- //这里注入port可时刻监控哪个服务被调用
- @Value("${server.port}")
- private int port;
- /**
- *降级:
- * 出现异常
- * 服务调用超时
- */
- @GetMapping("/findOne/{id}")
- //指定降级后调用的方法
- @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties ={
- //修改几秒后超时
- @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000"),
- //监控时间 默认5000 毫秒
- @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
- //失败次数。默认20次
- @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
- //失败率 默认50%
- @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
- })
- public Goods findOne(@PathVariable("id") int id){
- Goods goods = goodsService.findOne(id);
-
- //熔断
- //如果id==1,则出现异常,id !=1 则正常访问
- if(id == 1){
- //造个异常
- int i =3/0;
- }
-
- //降级
- //造个异常
- int i =3/0;
- //超时
- /*
- try{
- //休眠两秒
- Thread.sleep(2000);
- }catch (InterruptedException e){
- e.printStackTrace();
- }
- */
-
- //将端口号,设置到了商品标题上方便监控
- goods.setTitle(goods.getTitle()+" "+"port" + ":" + port);
-
- return goods;
- }
- /**
- * 定义降级方法
- *方法的返回值需要和原方法一样
- * 方法的参数需要和原方法一样
- */
- public Goods findOne_fallback(int id){
- Goods goods = new Goods();
- goods.setTitle("降级了~~~");
- return goods;
- }
- }


创建监控模块:
创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能
引入Turbine聚合监控起步依赖:
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>spring_cloud_parentartifactId>
- <groupId>com.gaogroupId>
- <version>1.0-SNAPSHOTversion>
- parent>
- <modelVersion>4.0.0modelVersion>
-
- <artifactId>hystrix-monitorartifactId>
-
- <properties>
- <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
- <java.version>1.8java.version>
- properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-turbineartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-maven-pluginartifactId>
- plugin>
- plugins>
- build>
-
- project>
application.yml
- spring:
- application.name: hystrix-monitor
- server:
- port: 8769
- turbine:
- combine-host-port: true
- # 配置需要被监控的服务名称列表
- app-config: hystrix-provider,hystrix-consumer
- cluster-name-expression: "'default'"
- aggregator:
- cluster-config: default
- #instanceUrlSuffix: /actuator/hystrix.stream
- eureka:
- client:
- serviceUrl:
- defaultZone: http://localhost:8761/eureka/
启动类:
- package com.itheima;
-
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
- import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
- import org.springframework.cloud.netflix.turbine.EnableTurbine;
-
- @SpringBootApplication
- @EnableEurekaClient
-
- @EnableTurbine //开启Turbine 很聚合监控功能
- @EnableHystrixDashboard //开启Hystrix仪表盘监控功能
- public class HystrixMonitorApp {
-
- public static void main(String[] args) {
- SpringApplication.run(HystrixMonitorApp.class, args);
- }
-
- }
添加依赖
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
- dependency>
启动类里配置Bean再添加启动注解
- //启动类
- @EnableEurekaClient
- @SpringBootApplication
- @EnableCircuitBreaker//开启Hystrix熔断器
- @EnableHystrixDashboard//开启Hystrix仪表盘监控功能
- public class ProviderApp {
- public static void main(String[] args){
- SpringApplication.run(ProviderApp.class,args);
- }
- @Bean
- public ServletRegistrationBean getServlet() {
- HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
- ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
- registrationBean.setLoadOnStartup(1);
- registrationBean.addUrlMappings("/actuator/hystrix.stream");
- registrationBean.setName("HystrixMetricsStreamServlet");
- return registrationBean;
- }
- }
consumer OrderController这里注入的goodsFeignClient会报红,可以忽略。
- //服务的调用方
- @RestController
- @RequestMapping("/order")
- public class OrderController {
-
- @Autowired
- private GoodsFeignClient goodsFeignClient;
-
- @GetMapping("/goods/{id}")
- public Goods findGoodsById(@PathVariable("id") int id){
-
- //3.调用方法
- //Goods goods = restTemplate.getForObject(url,Goods.class);
- Goods goods = goodsFeignClient.findGoodById(id);
- return goods;
- }
- }



web界面输入Url地址:
http://localhost:8769/turbine.stream 监控所有监管的服务
http://localhost:9000/actuator/hystrix.stream 监控单个服务consumer
http://localhost:8000/actuator/hystrix.stream 监控provider
实心圆:他有颜色大小区分,分别代表实例的监控程序和流量大小。他从上图所示健康度从绿色 黄色 橙色 红色递减。通过实心球的展示我们可以在大量的实例中快速的发现故障实例和高压力实例
曲线: 用来记录两分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。