什么是Hystrix

在分布式系统中,每个服务都可能会调用很多其他服务,被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很常见的。
Hystrix是Netflix公司开源的一个项目,它提供了熔断器功能,能够解决分布式系统中出现联动故障,Hystrix是通过隔离服务的访问点阻止故障,并提供故障解决方案,从而提高分布式系统弹性。
    Hystrix可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制。Hystrix通过将依赖服务进行资源隔离,进而阻止某个依赖服务出现故障时在整个系统所有的依赖服务调用中进行蔓延;同时Hystrix 还提供故障时的 fallback 降级机制。
    总而言之,Hystrix 通过这些方法帮助我们提升分布式系统的可用性和稳定性。

Hystrix解决了什么问题

   在分布式系统中,可能有几十个服务相互依赖。这些服务由于某些原因导致不可用。如果系统不隔离不可用的服务,则可能会导致整个系统不可用。<br />       在高并发情况下,单个服务的延迟会导致整个请求都处于延迟状态,可能在几秒钟就使整个线程处于负载饱和状态。<br />       某个服务的单点故障会导致用户的请求处于阻塞状态,最终的结果就是整个服务的线程资源消耗殆尽。由于服务的依赖性,会导致依赖该故障服务的其他服务也处于线程阻塞状态,最终导致这些依赖服务的线程资源消耗殆尽,直到不可用,从而导致整个服务系统不可用,这就是雪崩效应。<br />       为了防止雪崩效应,因而产生了熔断器模型。Hystrix是业界表现非常好的一个熔断器模型实现的开源组件,是SpringCloud组件不可缺少的一部分。<br />

Hystrix设计原则

  • 防止单个服务故障耗尽整个服务的Servlet容器(Tomcat/Jetty)的线程资源。
  • 快速失败机制,如果某个服务出现故障,则调用该服务的请求迅速失败,而不是线程等待。
  • 提供回退方案(fallback),在请求发生故障时,提供设定好的回退方案。
  • 使用熔断机制,防止故障扩散到其他服务。
  • 提供熔断器的监控组件Hystrix Dashboard,近实时的监控,报警以及运维操作。

Hystrix工作服原理


首先,当服务的某个API接口的失败次数在一定时间内小于设定的阈值时,熔断器处于关闭状态,该API接口正常提供服务。当该API接口处理请求失败的次数大于设定阈值时,Hystrix判定该接口出现了故障,打开熔断器。这时请求该API接口会执行快速失败的逻辑(fallback的逻辑),不执行业务,请求的线程不会处于阻塞状态。 处于打开状态的熔断器,一段时间后会处于半打开状态,并将一定数量的请求执行正常逻辑。剩余的请求会执行快速失败,若执行正常请求的逻辑失败了,则熔断器继续打开。如果执行成功了,则将熔断器关闭,这样设计的熔断器则具备了自我修复的能力。

在RestTemplate和Ribbon作为服务消费者时使用Hystrix

新建父Module和4个子Module,项目结构如下图

父Module主要用来引入DependencyManagement

  <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</dependencyManagement>

创建EurekaServer

创建子Module, try-spring-cloud-eureka-server。
pom.xml

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>

application.yml

server:
port: 7001
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka # 注册中心端口7001
register-with-eureka: false
fetch-registry: false

Main 函数入口

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

创建Student Server Provider

创建子Module,try-spring-cloud-student-service
pom.xml

 <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>

application.yml

server:
port: 8001
spring:
application:
name: CLOUD-STUDENT-SERVICE eureka:
client:
fetch-registry: false
register-with-eureka: true # 注册进Eureka Server
service-url:
defaultZone: http://localhost:7001/eureka # 单机版指向7001

Main函数

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

Controller, 我在这里先返回了一个字符串用来测试使用。

@RestController
@RequestMapping("/student")
public class StudentController { @GetMapping("/version")
public String version(){
return "8001,202008182343";
}
}

创建Ribbon Client

创建子Module,try-spring-cloud-ribbon-hystrix。 该模块下,我们基于RestTemplate和Ribbon作为消费者调用服务,先测试下服务正常时访问逻辑, 和前面两个Module不同,这个Module里需要引入spring-cloud-starter-netflix-hystrix依赖。
pom.xml

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</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-netflix-hystrix</artifactId>
</dependency>
</dependencies>

application.yml

server:
port: 8087 spring:
application:
name: STUDENT-CONSUMER
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka # 服务注册中心地址

Main函数,这里增加EnableHystrix注解,开启熔断器。

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

Ribbon调用配置,关键注解LoadBalanced。

@Configuration
public class MyWebConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

Controller, 这里调用CLOUD-STUDENT-SERVICE的version()接口,同时增加了HystrixCommand注解,设置了属性fallbackMethod, 如果方法调用失败则执行快速失败方法getErrorInfo。

@RestController
@RequestMapping("/student")
public class StudentController { @Autowired
RestTemplate restTemplate; /**
* 使用HystrixCommand注解,设置服务调用失败时回调方法(getErrorInfo)
* **/
@GetMapping("/version")
@HystrixCommand(fallbackMethod = "getErrorInfo")
public String version() {
System.out.println("Ribbon调用前");
String result = restTemplate.getForObject("http://CLOUD-STUDENT-SERVICE/student/version", String.class);
System.out.println("Ribbon调用后,返回值:" + result);
return result;
} public String getErrorInfo(){
return "Network error, please hold on...";
}
}

依此启动Eureka-Server、Student-Service、Ribbon-Hystrix先测试下服务正常调用逻辑。
访问http://localhost:8087/student/version, 如果正常输出8001,202008182343字符串,则说明服务目前正常。然后我们在停止Student-Service(8001)的服务,再访问下8087服务, 结果输出Network error, please hold on... 则说明熔断器已经生效。

HystrixCommand注解参数

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {
#配置全局唯一标识服务的名称
String groupKey() default ""; #配置全局唯一标识服务分组的名称,比如,库存系统、订单系统、系统用户就是一个单独的服务分组
String commandKey() default ""; #对线程池进行设定,细粒度的配置,相当于对单个服务的线程池信息进行设置,也可多个服务设置同一个threadPoolKey构成线程组
String threadPoolKey() default ""; #执行快速失败的回调函数,@HystrixCommand修饰的函数必须和这个回调函数定义在同一个类中,因为定义在了同一个类中,所以fackback method可以是public/private均可
String fallbackMethod() default ""; #配置该命令的一些参数,如executionIsolationStrategy配置执行隔离策略,默认是使用线程隔离
HystrixProperty[] commandProperties() default {}; #线程池相关参数设置,具体可以设置哪些参数请见:com.netflix.hystrix.HystrixThreadPoolProperties
HystrixProperty[] threadPoolProperties() default {}; #调用服务时,除了HystrixBadRequestException之外,其他@HystrixCommand修饰的函数抛出的异常均会被Hystrix认为命令执行失败而触发服务降级的处理逻辑(调用fallbackMethod指定的回调函数),所以当需要在命令执行中抛出不触发降级的异常时来使用它,通过这个参数指定,哪些异常抛出时不触发降级(不去调用fallbackMethod),而是将异常向上抛出
Class<? extends Throwable>[] ignoreExceptions() default {}; #定义hystrix observable command的模式
ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; #任何不可忽略的异常都包含在HystrixRuntimeException中
HystrixException[] raiseHystrixExceptions() default {}; #默认的回调函数,该函数的函数体不能有入参,返回值类型与@HystrixCommand修饰的函数体的返回值一致。如果指定了fallbackMethod,则fallbackMethod优先级更高
String defaultFallback() default "";
}

## 在OpenFeign作为服务消费者时使用Hystrix
创建子Module, try-spring-cloud-openfeign-hystrix,这个节点使用OpenFeign作为服务消费者时使用Hystrix, OpenFeign里已经依赖了Hystrix,所以这里不需要再单独引入,只需要引入spring-cloud-starter-openfeign即可。
pom.xml
```java

junit
junit

org.springframework.boot
spring-boot-starter-web

org.springframework.boot
spring-boot-starter-test

org.springframework.boot
spring-boot-starter-actuator

org.springframework.cloud
spring-cloud-starter-netflix-eureka-client

org.springframework.cloud
spring-cloud-starter-openfeign

```
```java
server:
port: 8087

spring:

application:

name: STUDENT-OPENFEIGN-CONSUMER

eureka:

client:

register-with-eureka: false

fetch-registry: true

service-url:

defaultZone: http://localhost:7001/eureka # 服务注册中心地址

feign:

hystrix:

enabled: true #在feign中开启hystrix

定义调用CLOUD-STUDENT-SERVICE的接口,也就是增加注解FeignClient,设置value和fallback属性。
```java
@FeignClient(value = "CLOUD-STUDENT-SERVICE",fallback = StudentFallbackService.class)
public interface StudentService { @GetMapping("/student/version")
String version();
}

StudentFallbackService

@Component
public class StudentFallbackService implements StudentService {
@Override
public String version() {
return "Network Error, I am callback service...";
}
}

Controller

@RestController
@RequestMapping("/student")
public class StudentController { @Autowired
StudentService studentService; @GetMapping("/version")
public String version(){
System.out.println("===openfeign 调用===");
return studentService.version();
}
}

Main函数

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

依次启动Eureka-Server, Student-Service,OpenFeign-Hystrix-Client,和上面Ribbon一样,先来测试下正常逻辑,访问http://localhost:8087/student/version. 输出8001,202008182343字符串说明服务调用正常,然后停掉Student-Service,再次访问接口,输出Network Error, I am callback service... 则说明基于OpenFeign的熔断器已经生效。

请求缓存功能@CacheResult

Hystrix还提供了请求缓存功能,当一些查询服务不可用时,可以调用缓存查询。@CacheResult需要和@HystrixCommand组合使用

注解 描述 属性
@CacheResult 该注解用来标记请求命令返回的结果应该被缓存,它必须与@HystrixCommand注解结合使用 cacheKeyMethod
@CacheRemove

| 该注解用来让请求命令的缓存失效,失效的缓存根据定义Key决定 | commandKey,
cacheKeyMethod |

| @CacheKey | 该注解用来在请求命令的参数上标记,使其作为缓存的Key值,如果没有标注则会使用所有参数。如果同事还是使用了@CacheResult和@CacheRemove注解的cacheKeyMethod方法指定缓存Key的生成,那么该注解将不会起作用 | value |

总结

  Hystrix现在已经宣布停止更细了,进入了维护模式,但是其性能也比较稳定了,spring官方推荐了[Resilience4J](https://github.com/resilience4j/resilience4j)、阿里的[Sentinel](https://github.com/alibaba/Sentinel)、[Spring Retry](https://github.com/spring-projects/spring-retry)作为替代方案。

SpringBoot + SpringCloud Hystrix 实现服务熔断的更多相关文章

  1. Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

    目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 ...

  2. JNPF.java前后端分离框架,SpringBoot+SpringCloud开发微服务平台

    JNPF.java版本采用全新的前后端分离架构模式.前后端分离已成为互联网项目开发的业界标准开发方式,通过 nginx+tomcat 等方式有效的进行解耦合,并且前后端分离会为以后的大型分布式架构.弹 ...

  3. springcloud组件之hystrix服务熔断,降级,限流

    hystrix 简介 Hystrix是什么 在分布式环境中,许多服务依赖项中的一些必然会失败.Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互.Hystrix通过 ...

  4. 《springcloud 四》服务保护机制

    服务保护机制SpringCloud Hystrix 微服务高可用技术 大型复杂的分布式系统中,高可用相关的技术架构非常重要. 高可用架构非常重要的一个环节,就是如何将分布式系统中的各个服务打造成高可用 ...

  5. 【springcloud】服务熔断与降级(Hystrix)

    转自:https://blog.csdn.net/pengjunlee/article/details/86688858 服务熔断 服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的 ...

  6. java框架之SpringCloud(5)-Hystrix服务熔断、降级与监控

    前言 分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败.不做任何处理的情况下,很容易导致服务雪崩. 服务雪崩:多个微服务之间调用的时候,假设 ...

  7. SpringCloud微服务(03):Hystrix组件,实现服务熔断

    本文源码:GitHub·点这里 || GitEE·点这里 写在前面:阅读本文前,你可能需要熟悉一下内容. 微服务组件:Eureka管理注册中心 微服务组件:Ribbon和Feign服务调用 Sprin ...

  8. Spring-cloud微服务实战【七】:服务熔断与降级hystrix

      在之前的文章中,我们先后介绍了eureka,ribbon,feign,使用eureka集群的方式来保证注册中心的高可用,在eureka中使用ribbon进行负载均衡,使用feign接口替换手动编码 ...

  9. SpringCloud Netflix (五) : Hystrix 服务熔断和服务降级

    什么是Hystrix 在分布式环境中,许多服务依赖项中的一些服务依赖不可避免地会失败.Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助您控制这些分布式服务之间的交互.Hystrix通过隔离服务 ...

随机推荐

  1. sourceTree安装、跳过bitbucket注册免登陆方法

    下载好以后,点击安装运行,会出现下面这个窗口 关掉这个窗口,打开C:\Users\{users}\AppData\Local\Atlassian\SourceTree(users是计算机的名字),新建 ...

  2. 那些年拿过的shell之springboot jolokia rce

    日穿扫描扫到一个spring boot actuator 可以看到有jolokia这个端点,再看下jolokia/list,存在type=MBeanFactory 关键字 可以使用jolokia-re ...

  3. luogu P6097 子集卷积 FST FWT

    LINK:子集卷积 学了1h多 终于看懂是怎么回事了(题解写的不太清楚 翻了好几篇博客才懂 一个需要用到的性质 二进制位为1个数是i的二进制数s 任意两个没有子集关系.挺显然. 而FST就是利用这个性 ...

  4. 7.9 NOI模拟赛 数列 交互 高精 字符串

    这是交互题 也是一个防Ak的题目 4个\(subtask\) 需要写3个不尽相同的算法. 题目下发了交互程序 所以调试的时候比较方便 有效防止\(CE\). 题目还有迷糊选手的点 数字位数为a 范围是 ...

  5. 一本通 高手训练 1782 分层图 状压dp

    LINK:分层图 很精辟的一道题 写的时候没带脑子 导致搞了半天不知道哪错了. 可以想到状压每次到某一层的状态 然后这个表示方案数 多开一维表示此时路径条数的奇偶即可. 不过显然我们只需要知道路径条数 ...

  6. dfs树

    dfs树是解决图中带环的利器. 前天CF的F题就是dfs树,但是当时我没有认真思考 觉着找到一个环过于困难 当时没有想到 也没理解dfs树的意义. 对于一张无向图求出一个dfs树 这个树有两种边 树边 ...

  7. Dynamics365 Field Service Work Order Theory

    Come from :https://neilparkhurst.com/2016/08/20/field-service-work-order-theory/ In this post I aim ...

  8. Java和C语言谁是编程语言的老大?

    最近,TIOBE 公布了 2020 年 7 月的编程语言排行榜. 本次排行榜的最大亮点就是:C语言击败Java,稳坐老大宝座! 这两年,编程语言排行榜榜首位置,不是C语言,就是Java. 以下为具体榜 ...

  9. 025_go语言中的通道同步

    代码演示 package main import "fmt" import "time" func worker(done chan bool) { fmt.P ...

  10. 简直骚操作,ThreadLocal还能当缓存用

    背景说明 有朋友问我一个关于接口优化的问题,他的优化点很清晰,由于接口中调用了内部很多的 service 去组成了一个完成的业务功能.每个 service 中的逻辑都是独立的,这样就导致了很多查询是重 ...