源码: https://gitee.com/GXQ205153964/Hystrix-parent.git
Hystrix概述:- hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)
- 级联失败: 当C服务出现问题(硬盘烧了,网络断了)不可用了,B依旧会不停的调用C,B的资源耗尽,导致B也出现问题,同理A。这种现象被称为雪崩。
预防雪崩
Hystix主要功能:问题:
这里有一个线程池对应3个服务,当哪个服务被调用时,线程池会分配一个线程运行。当C发生故障后线程池的线程依旧会执行C服务,从而导致线程池线程用完,从而导致BD服务也无法使用。
解决:
- 隔离:
线程池隔离:把A分成3个线程池分别对应三个服务,C坏了后,BD不会收到影响。
信号量隔离:对BCD加一个阀门,只允许一定的数量的人经行访问,超过就不能访问了,从而阻止C将所有的线程池资源耗尽。
- 降级 (异常,超时等)自己写个降级方案,在服务调用方和提供方都要写,网络不通时。降级就是执行自己B计划,预案。
- 熔断 当C服务出现错误频率较高时,Hystrix直接将C的所有服务全部拒绝,C修复后,熔断器会自动将C恢复成原来样子,正常运行。熔断机制,用于监控微服务调用情况,当失败的情况打到预定的阀值(5秒失败20次),会打开短路器,拒绝所有请求,知道服务回复正常为止。
- 限流 限制多少人/服务访问
(c降级方案)
流程:
- 在服务提供方,引入hystrix依赖
- 定义降级方法
- 使用@HystrixCommand注解配置降级方法
- 在启动类上开启Hystrix功能:@EnableCircuitBreker
基础代码构建
SpringCloud EurekeServer Consumer和provider
C降级方案搭建provider:
pom.xml
org.springframework.cloud spring-cloud-starter-netflix-hystrix
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; } }降级——Hystrix降级-服务提供方
- 在服务提供方,引入hystrix依赖(consumer使用了feign,而feign里已经集成了Hystrix,不用再引入feign依赖了,如果没有过使用feign,按照provider写)
- 定义降级方法
- 使用@HystrixCommand注解配置降级方法
- 在启动类上开启Hystrix功能:@EnableCircuitBreaker
consumer使用了feign,而feign里已经集成了Hystrix,不用再引入feign依赖了
A级降级方案搭建开启feign对hystrix的支持
#开启feign对hystrix的支持 feign: hystrix: enabled: true
pom.xml
org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-actuatororg.springframework.cloud spring-cloud-starter-netflix-eureka-clientorg.springframework.cloud spring-cloud-starter-openfeign
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; //超时 //将端口号,设置到了商品标题上方便监控 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; //超时 //将端口号,设置到了商品标题上方便监控 goods.setTitle(goods.getTitle()+" "+"port" + ":" + port); return goods; } public Goods findOne_fallback(int id){ Goods goods = new Goods(); goods.setTitle("降级了~~~"); return goods; } }熔断监控 简介
- Hystrix提供了Hystrix-dashbopard功能,用于实时监控微服务运行状态
- 但是Hystrix-dashboard只能监控一个微服务
- Netflix还提供了Trurbine进行聚合监控
创建监控模块:
创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能
引入Turbine聚合监控起步依赖:
spring_cloud_parent com.gao 1.0-SNAPSHOT 4.0.0 hystrix-monitorUTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboardorg.springframework.cloud spring-cloud-starter-netflix-turbineorg.springframework.boot spring-boot-starter-actuatororg.springframework.cloud spring-cloud-starter-netflix-eureka-clientorg.springframework.boot spring-boot-starter-testtest org.springframework.boot spring-boot-maven-plugin
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); } }分别修改hystrix-provider和hystrix-consumer模块
添加依赖
org.springframework.boot spring-boot-starter-actuatororg.springframework.cloud spring-cloud-starter-netflix-hystrixorg.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboard
启动类里配置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; } }
- 测试结果:
- 分别访问:以下url显示下面情况说明监控到了对应服务下的数据
- localhost:8000/actuator/hystrix.stream
- localhost:9000/actuator/hystrix.stream
- localhost:8769/turbine.stream
web界面输入Url地址:
http://localhost:8769/turbine.stream 监控所有监管的服务
http://localhost:9000/actuator/hystrix.stream 监控单个服务consumer
http://localhost:8000/actuator/hystrix.stream 监控provider
-
实心圆:他有颜色大小区分,分别代表实例的监控程序和流量大小。他从上图所示健康度从绿色 黄色 橙色 红色递减。通过实心球的展示我们可以在大量的实例中快速的发现故障实例和高压力实例
曲线: 用来记录两分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。