欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

分布式微服务的 Hystrix断路器

程序员文章站 2022-04-15 17:45:45
Hystrix断路器服务雪崩多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就是所谓的 “扇出”,如果扇出的链路上某个微服务的调用时间过长或者不可用,对微服务A的调用就会占有越来越多的系统资源,进而引起系统奔溃,所谓的 “雪崩效应”。对于高流量的应用来说,单一的后端依赖坑会导致所有服务器上的所有资源都在几秒内饱和。更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发送更多的级联故障。这些表示需要对...

Hystrix断路器

分布式微服务的 Hystrix断路器

服务雪崩
  • 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就是所谓的 “扇出”,如果扇出的链路上某个微服务的调用时间过长或者不可用,对微服务A的调用就会占有越来越多的系统资源,进而引起系统奔溃,所谓的 “雪崩效应”。
  • 对于高流量的应用来说,单一的后端依赖坑会导致所有服务器上的所有资源都在几秒内饱和。更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发送更多的级联故障。这些表示需要对故障和延迟进行隔离和管理,以便单个依赖关系失败,不能导致整个应用程序奔溃
  • 所以 通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收-流量,然后这个有问题的模块还调用了其他模块,这样就会发生级联故障,或者叫雪崩。

简介
  • Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能保证一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。

  • “断路器 ” 本身是一种开关装置,当某个服务单元发生故障的时候,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期,可处理的备选响应(FallBack),而不是长时间的等待护着抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免故障在分布式系统中蔓延

  • 功能:服务降级,服务熔断,接近实时的监控,限流,隔离等

Hystrix重要概念
服务降级(fallback)

提供者和消费者都可以进行服务降级。(一般都是放在客户端(消费者))

分布式微服务的 Hystrix断路器

服务熔断(break)

分布式微服务的 Hystrix断路器

服务限流(flowlimit)

分布式微服务的 Hystrix断路器
新建客户端 cloud-provider-hystrix-payment8001 模块

  1. 引入POM (在客户端(消费者使用))
<!-- hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> 
  1. yml配置
server: port: 8001 spring: application: name: cloud-provider-hystrix-payment
	

eureka: client: register-with-eureka: true fetch-registry: true service-url: #单机版
      defaultZone: http://localhost:7001/eureka 
  1. 主启动类
@EnableEurekaClient @SpringBootApplication public class PaymentHystrixMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class, args); } } 
  1. service
@Service public class PaymentService { //正常访问方法 public String paymentInfo_OK(Integer id){ return "线程池:" + Thread.currentThread().getName() + "\tpaymentInfo_OK,id:" + id; } //超时访问方法 public String paymentInfo_TimeOut(Integer id){ int timeNumber = 3; try { TimeUnit.SECONDS.sleep(timeNumber); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:" + Thread.currentThread().getName() + "\tpaymentInfo_TimeOut,id:" + id + ",耗时:" + timeNumber + "秒"; } } 
  1. controller
@Slf4j @RestController public class PaymentController { @Resource PaymentService paymentService; @Value("${server.port}") //spring的@Value注解 private String ServerPort; @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentService.paymentInfo_OK(id); log.info("******result:" + result); return result; } @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(Integer id){ String result = paymentService.paymentInfo_OK(id); log.info("******result:" + result); return result; } } 
  1. 启动7001和8001

http://localhost:8001/payment/hystrix/ok/1

分布式微服务的 Hystrix断路器

== http://localhost:8001/payment/hystrix/timeout/1==
分布式微服务的 Hystrix断路器

进行高并发测试:
分布式微服务的 Hystrix断路器

分布式微服务的 Hystrix断路器
然后去访问http://localhost:8001/payment/hystrix/ok/1,访问速度变慢了。


新建消费者

新建消费者模块 cloud-consumer-feign-hystrix-order80

  1. 引入POM
<dependencies> <!-- openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- 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-client</artifactId> </dependency> <!-- 引用自己定义的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>com.angenin.springcloud</groupId> <artifactId>cloud-api-commons</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> 
  1. yml文件
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://localhost:7001/eureka

#需要加上,否则会报错
ribbon: ReadTimeout: 4000 ConnectTimeout: 4000 
  1. 主启动类
@EnableEurekaClient @EnableFeignClients @SpringBootApplication public class OrderHystrixMain80 { public static void main(String[] args) { SpringApplication.run(OrderHystrixMain80.class, args); } } 
  1. service
@Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT") public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id); } 
  1. controller
@Slf4j @RestController public class OrderHystrixController { @Resource private PaymentHystrixService paymentHystrixService; @GetMapping("/consumer/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_OK(id); return result; } @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } } 
  1. 启动jmeter,然后再进行测试

分布式微服务的 Hystrix断路器

安装JMeter
JMeter下载地址:http://jmeter.apache.org/download_jmeter.cgi

下载tgz和zip都可以:

分布式微服务的 Hystrix断路器
启动jmeter 测试

分布式微服务的 Hystrix断路器
故障现象、导致原因以及解决

现象:
分布式微服务的 Hystrix断路器
解决:

分布式微服务的 Hystrix断路器

服务降级

分布式微服务的 Hystrix断路器

提供者 (8001模块)
  1. 修改8001中PaymentService的paymentInfo_TimeOut方法,并添加paymentInfo_TimeOutHandler方法:
 @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = { //设置自身超时调用时间的峰值为3秒,峰值内可以正常运行,超过了需要有兜底的方法处理,服务降级fallback @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public String paymentInfo_TimeOut(Integer id){ int timeNumber = 5; //int i = 1 / 0; try { TimeUnit.SECONDS.sleep(timeNumber); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:" + Thread.currentThread().getName() + "\tpaymentInfo_TimeOut,id:" + id + ",耗时:" + timeNumber + "秒"; } public String paymentInfo_TimeOutHandler(Integer id){ return "8001提供者,线程池:" + Thread.currentThread().getName() + "\tpaymentInfo_TimeOutHandler系统繁忙,请稍后再试,id:" + id; } 
  1. 然后在8001的主启动类上添加@EnableCircuitBreaker注解,启用断路器。

分布式微服务的 Hystrix断路器

消费者 (80模块)

分布式微服务的 Hystrix断路器

  1. yml添加 :
feign: hystrix: enabled: true 
  1. 在主启动类添加@EnableHystrix注解。

  2. 修改OrderHystrixController的paymentInfo_TimeOut方法,并添加paymentTimeOutFallbackMethod方法:

 @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500") }) @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){ return "消费者80,支付系统繁忙"; } 

启动7001,8001,80,http://localhost/consumer/payment/hystrix/timeout/1(如果是提供者那边出问题,并且消费者设置了fallback,会优先进入消费者的fallback)

分布式微服务的 Hystrix断路器


分布式微服务的 Hystrix断路器

代码膨胀的解决办法:

分布式微服务的 Hystrix断路器

分布式微服务的 Hystrix断路器


服务熔断

分布式微服务的 Hystrix断路器

  1. 在8001的PaymentService中添加
在这里插入代码片 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //请求总数阈值(默认20) @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗口期(休眠多久进入半开模式(单位毫秒,默认5秒)) @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //请求次数的错误率达到多少跳闸(百分率%,默认50%) }) public String paymentCircuitBreaker(@PathVariable("id") Integer id) { if(id < 0){ throw new RuntimeException("****id 不能为负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能为负数,请稍后再试, id: " + id; } 
  1. 在8001的PaymentController中添加
@GetMapping("/payment/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id){ String result = paymentService.paymentCircuitBreaker(id); log.info("******result:" + result); return result; } 
  1. 启动7001和8001
    http://localhost:8001/payment/circuit/-1(输入超过6次进入熔断)
    分布式微服务的 Hystrix断路器
  • 熔断10秒内就算是正确的请求也返回错误信息。
  • 10秒后进入半开模式,对请求进行处理,此时如果是正确的请求,那么就关闭熔断,否则再次进入熔断,10秒后再次开启半开模式,对请求进行处理,直到半开模式处理到正确请求。

总结

https://martinfowler.com/bliki/CircuitBreaker.html

分布式微服务的 Hystrix断路器

  • 我的总结:如果请求次数的错误率超过指定值,开启熔断,经过一段时间后,变为半开模式,然后放进一个请求进行处理,如果请求处理成功,关闭熔断;如果还是报错,继续进入熔断,再经过一段时间后,变为半开模式,再进行对下一个请求进行处理,一直在熔断,半开模式来回切换,直到请求成功,关闭熔断。

分布式微服务的 Hystrix断路器

  • 官网步骤:

分布式微服务的 Hystrix断路器

  • 断路器在什么情况下开始起作用:
    分布式微服务的 Hystrix断路器
    分布式微服务的 Hystrix断路器
  • 断路器开启或关闭的条件:
    分布式微服务的 Hystrix断路器
    断路器打开之后:

分布式微服务的 Hystrix断路器

服务限流

会在后面高级篇alibaba的Sentinel讲解。

Hystrix工作流程:

分布式微服务的 Hystrix断路器
分布式微服务的 Hystrix断路器

服务监控HystrixDashboard

简介

分布式微服务的 Hystrix断路器


仪表盘9001

  1. 新建模块 cloud-consumer-hystrix-dashboard9001

  2. pom

<dependencies> <!-- hystrix仪表盘图形化 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>com.angenin.springcloud</groupId> <artifactId>cloud-api-commons</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> 
  1. http://localhost:9001/hystrix

分布式微服务的 Hystrix断路器
断路器演示(服务监控hystrixDashboard)
注意:所有微服务提供者都需要在pom中引入监控依赖。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 

在8001的主启动类中添加:

 /**
    * 此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
    * ServletRegistrationBean因为SpringBoot的默认路径不是 “/hystrix.stream"
    * 只要在自己的项目里配置上下的servlet就可以了
    */ @Bean public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet() ; ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/hystrix.stream"); registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; } 

分布式微服务的 Hystrix断路器

在浏览器输入http://localhost:8001/payment/circuit/1和http://localhost:8001/payment/circuit/-1

分布式微服务的 Hystrix断路器
分布式微服务的 Hystrix断路器
分布式微服务的 Hystrix断路器

本文地址:https://blog.csdn.net/qq_41977838/article/details/108207975

相关标签: springcloud springC