✨✨个人主页:沫洺的主页
📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏
📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏
📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏
💖💖如果文章对你有所帮助请留下三连✨✨
衔接上篇: [Spring Cloud] Ribbon介绍与定义负载均衡_沫洺的博客-CSDN博客
💐Hystrix介绍
Hystrix中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。
Hystrix是一个容错组件,实现了超时机制和断路器模式。
Hystrix被设计的目标是:
- 对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。
- 在复杂的分布式系统中阻止级联故障。
- 快速失败,快速恢复。
- 回退,尽可能优雅地降级。
- 启用近实时监控、警报和操作控制。
Hystrix提供了熔断和降级。
接下来了解一下Hystrix的三大特性: 降级,熔断,隔离
🌿服务降级
参考文章: 微服务架构—服务降级
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和业务有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作
服务降级主要用于什么场景呢?
当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,我们可以将一些 不重要 或 不紧急 的服务或任务(非核心业务(负载过高)或者故障业务)进行服务的 延迟使用 或 暂停使用。就相当于try catch一样的逻辑,当然hystrix底层使用aop来实现的。
说白了服务降级就是系统有限的资源的合理协调,来保证核心服务和业务正常运作或高效运作
🌾服务熔断
参考文章: 什么是服务熔断
参考文章: 微服务的熔断原理与实现
熔断这一概念来源于电子工程中的断路器,当电路超负荷运行时,保险丝会自动的断开,从而保证电路中的电器不受损害
在互联网系统中,当下游服务(被调用方)因访问压力过大而响应变慢或失败,上游服务(调用方)为了保护系统整体的可用性,可以暂时切断对下游服务(被调用方)的调用。也就是说熔断机制是应对雪崩效应的一种微服务链路保护机制
这种牺牲局部,保全整体的措施就叫做熔断
服务调用方为每一个调用服务 (调用路径) 维护一个状态机,在这个状态机中有三个状态:
- 关闭 (Closed):在这种状态下,我们需要一个计数器来记录调用失败的次数和总的请求次数,如果在某个时间窗口内,失败的失败率达到预设的阈值,则切换到断开状态,此时开启一个超时时间,当到达该时间则切换到半关闭状态,该超时时间是给了系统一次机会来修正导致调用失败的错误,以回到正常的工作状态。在关闭状态下,调用错误是基于时间的,在特定的时间间隔内会重置,这能够防止偶然错误导致熔断器进去断开状态
- 打开 (Open):在该状态下,发起请求时会立即返回错误,一般会启动一个超时计时器,当计时器超时后,状态切换到半打开状态,也可以设置一个定时器,定期的探测服务是否恢复
- 半打开 (Half-Open):在该状态下,允许应用程序一定数量的请求发往被调用服务,如果这些调用正常,那么可以认为被调用服务已经恢复正常,此时熔断器切换到关闭状态,同时需要重置计数。如果这部分仍有调用失败的情况,则认为被调用方仍然没有恢复,熔断器会切换到关闭状态,然后重置计数器,半打开状态能够有效防止正在恢复中的服务被突然大量请求再次打垮
🍃服务降级和服务熔断区别
实际上服务熔断 和 服务降级 没有任何关系,就像 java 和 javaScript
参考文章: 服务降级与服务熔断区别
- 触发原因不一样,服务熔断由链路上某个服务引起的,服务降级是从整体的负载考虑
- 管理目标层次不一样,服务熔断是一个框架层次的处理,服务降级是业务层次的处理
- 实现方式不一样,服务熔断一般是自我熔断恢复,服务降级相当于人工控制
- 触发原因不同 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
服务熔断是应对系统服务雪崩的一种保险措施,给出的一种特殊降级措施。而服务降级则是更加宽泛的概念,主要是对系统整体资源的合理分配以应对压力。
服务熔断是服务降级的一种特殊情况,他是防止服务雪崩而采取的措施。系统发生异常或者延迟或者流量太大,都会触发该服务的服务熔断措施,链路熔断,返回兜底方法。这是对局部的一种保险措施。
服务降级是对系统整体资源的合理分配。区分核心服务和非核心服务。对某个服务的访问延迟时间、异常等情况做出预估并给出兜底方法。这是一种全局性的考量,对系统整体负荷进行管理。
🍁Hystrix隔离策略
每当向服务发起一个请求时,就是会发起一个http请求,每一个http请求就要开启一个线程,然后等待服务返回信息,这容易导致线程的堆积,所以就可以用http的URI作为一个标识,然后相同的URI可以开启一个线程池,然后线程池中限定线程数,这样就可以设置拒绝策略,当线程池满了,就可以快速的抛出异常或者拒绝请求,用线程池做到线程隔离来达到限流。
🍂Hystrix使用
参考文章: SpringCloud--Hystrix--断路器--01
参考文章: SpringCloud--Hystrix--断路器--02
父模块pom声明子模块
<module>spring-cloud-hystrix</module>
创建子模块spring-cloud-hystrix
pom.xml添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.moming</groupId> <artifactId>spring-cloud-root</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>spring-cloud-hystrix</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
启动类添加@EnableHystrix注解,启用Hystrix
@SpringBootApplication @EnableHystrix public class HystrixApp { public static void main(String[] args) { SpringApplication.run(HystrixApp.class, args); } }
编写测试接口
在接口上使用@HystrixCommand注解,进行服务降级的配置
参数: fallbackMethod
@RestController public class Test { @GetMapping("/test") @HystrixCommand(fallbackMethod = "hello_fallback") public String hello(){ return "原方法"; } public String hello_fallback(){ return "兜底方法"; } }
运行访问接口,此时服务调用正常
接下来模拟服务异常
@RestController public class Test { @GetMapping("/test") @HystrixCommand(fallbackMethod = "hello_fallback") public String hello(){ int i = 1/0; return "原方法"; } public String hello_fallback(){ return "兜底方法"; } }
再次访问
如果将异常进行try-catch处理,就会感知不到异常,结果还是原方法
@RestController public class Test { @GetMapping("/test") @HystrixCommand(fallbackMethod = "hello_fallback") public String hello(){ try { int i = 1/0; } catch (Exception e) { e.printStackTrace(); } return "原方法"; } public String hello_fallback(){ return "兜底方法"; } }
其实可以理解为兜底的作用,你不行的话就我来
注意兜底方法和原方法的入参和返回值类型要保持一致,只是方法名不同
参数: commandProperties
@RestController public class Test { @GetMapping("/test") @HystrixCommand(fallbackMethod = "hello_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //开启熔断器 @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value ="30000"), //统计时间窗 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "3"), //统计时间窗内最小请求次数阈值 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //休眠时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "30"), //时间窗内失败阈值百分比 //执行隔离线程超时 @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "3000") }) public String hello(@RequestParam Integer time){ ThreadUtil.sleep(time*1000); return "原方法"; } public String hello_fallback(Integer time){ return "兜底方法"; } }
运行访问
localhost:8080/test?time=1 模拟在隔离线程指定时间3秒内,模拟正常访问
localhost:8080/test?time=4 模拟超出隔离线程指定时间3秒,模拟失败访问,执行兜底方法
大致流程就是在30秒内,且超过访问最小此时3次,在访问5次时(其中2次正常,3次失败)超过失败阈值30%,开启熔断机制,开启后有10秒的休眠期,之后再次正常访问恢复正常状态,如果休眠期过后还是进行失败访问,那么继续开启熔断,10秒休眠期