SpringCloud - Hystrix断路器-服务熔断与降级和HystrixDashboard

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringCloud - Hystrix断路器-服务熔断与降级和HystrixDashboard

多位微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他微服务,这就是所谓的"扇处"。如果扇处的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃—所谓的"雪崩效应"。

对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上面的所有资源在几秒钟内饱和比失败更糟糕的是这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

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


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


【1】服务熔断

熔断机制是应对雪崩效应的一种微服务链路保护机制

当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务调用的状况,当失败的调用到一定阈值就会启动熔断机制(默认是5秒内20次调用失败就会启动熔断机制)。

熔断机制的注解:@HystrixCommand。

① 参考/microservicecloud-provider-dept-8001创建/microservicecloud-provider-dept-hystrix-8001

基础代码延用上篇博文Feign负载均衡与Ribbon代码


② 添加Hystrix依赖

  <dependencies>
    <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
    <dependency>
      <groupId>com.web.springcloud</groupId>
      <artifactId>microservicecloud-api</artifactId>
      <version>${project.version}</version>
    </dependency>
    <!-- actuator监控信息完善 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Hystrix -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    <!-- 将微服务provider侧注册进eureka -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jetty</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</groupId>
      <artifactId>springloaded</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  </dependencies>

③ yml文件配置

server:
  port: 8001
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.web.springcloud.entities    # 所有Entity别名类所在包
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
spring:
   application:
    name: microservicecloud-dept
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver              # mysql驱动包
#    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
    username: root
    password: 123456
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: true
    testOnReturn: false
    poolPreparedStatements: true
    #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#    dbcp2:
#      min-idle: 5                                           # 数据库连接池的最小维持连接数
#      initial-size: 5                                       # 初始化连接数
#      max-total: 5                                          # 最大连接数
#      max-wait-millis: 200                                  # 等待连接获取的最大超时时间
eureka:
  client: #客户端注册进eureka服务列表内
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/      
#      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: microservicecloud-dept8001-hystrix # 自定义服务实例Id
    prefer-ip-address: true     #访问路径可以显示IP地址     
# http://192.168.2.100:8001/info优化显示
info: 
  app.name: web-microservicecloud
  company.name: www.web.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

项目结构如下图:



④ 修改DeptController

@RestController
public class DeptController
{
  @Autowired
  private DeptService service = null;
  @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
  //一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod中的指定方法
  @HystrixCommand(fallbackMethod = "processHystrix_Get")
  public Dept get(@PathVariable("id") Long id)
  {
    Dept dept = this.service.get(id);
    if (null == dept) {
      throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
    }
    return dept;
  }
  public Dept processHystrix_Get(@PathVariable("id") Long id)
  {
    Dept dept = new Dept();
    dept.setDeptno(id);
    dept.setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand");
    dept.setDb_source("no this database in MySQL");
    return dept;
  }
}

⑤ 主程序类添加熔断支持

@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker //对Hystrix熔断机制支持
public class DeptProvider8001_Hystrix_App
{
  public static void main(String[] args)
  {
    SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
  }
}

⑥ 测试

首先启动三个服务中心7001 7002 7003然后启动/microservicecloud-provider-dept-hystrix-8001,接着启动/microservicecloud-consumer-dept-80,浏览器使用消费者请求一个数据库中不存在的记录。


【2】服务降级

一句话简要描述:整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。

服务降级处理是在客户端(消费者)完成的与服务端没有关系。

参考【1】服务熔断的处理方式,会发现这种方式是很可怕的。第一如果有多个方法,对应的FallBack方法也会随之膨胀;第二异常处理与业务逻辑高耦合,完全不符合Spring AOP面向切面的思想。

上面说了,服务降级是在客户端(消费者)处理的,又需要与业务解耦,使用面向切面的思想。再次参考@FeignClient注解源码:

/**
 * Annotation for interfaces declaring that a REST client with that interface should be
 * created (e.g. for autowiring into another component). If ribbon is available it will be
 * used to load balance the backend requests, and the load balancer can be configured
 * using a <code>@RibbonClient</code> with the same name (i.e. value) as the feign client.
 *
 * @author Spencer Gibb
 * @author Venil Noronha
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
  /**
   * The name of the service with optional protocol prefix. Synonym for {@link #name()
   * name}. A name must be specified for all clients, whether or not a url is provided.
   * Can be specified as property key, eg: ${propertyKey}.
   */
  @AliasFor("name")
  String value() default "";
  /**
   * The service id with optional protocol prefix. Synonym for {@link #value() value}.
   *
   * @deprecated use {@link #name() name} instead
   */
  @Deprecated
  String serviceId() default "";
  /**
   * The service id with optional protocol prefix. Synonym for {@link #value() value}.
   */
  @AliasFor("value")
  String name() default "";
  /**
   * Sets the <code>@Qualifier</code> value for the feign client.
   */
  String qualifier() default "";
  /**
   * An absolute URL or resolvable hostname (the protocol is optional).
   */
  String url() default "";
  /**
   * Whether 404s should be decoded instead of throwing FeignExceptions
   */
  boolean decode404() default false;
  /**
   * A custom <code>@Configuration</code> for the feign client. Can contain override
   * <code>@Bean</code> definition for the pieces that make up the client, for instance
   * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
   *
   * @see FeignClientsConfiguration for the defaults
   */
  Class<?>[] configuration() default {};
  /**
   * Fallback class for the specified Feign client interface. The fallback class must
   * implement the interface annotated by this annotation and be a valid spring bean.
   */
  Class<?> fallback() default void.class;
/**注意这里注释!!!!*/
  /**
   * Define a fallback factory for the specified Feign client interface.
   * //为指定的 Feign客户端接口定义一个fallback factory。
   * The fallback factory must produce instances of fallback classes that implement the interface
   * annotated by {@link FeignClient}. 
   * // 该工程必须产生一个标注了@FeignClient注解接口的实现类的实例。
   * The fallback factory must be a valid spring bean.
   *// 该工厂必须是一个可用的Spring bean--要注册进容器
   * @see feign.hystrix.FallbackFactory for details.
   */
  Class<?> fallbackFactory() default void.class;
  /**
   * Path prefix to be used by all method-level mappings. Can be used with or without
   * <code>@RibbonClient</code>.
   */
  String path() default "";
  /**
   * Whether to mark the feign proxy as a primary bean. Defaults to true.
   */
  boolean primary() default true;
}

解决方案如下:

① 修改/microservicecloud-api工程,根据已有的DeptClientService新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory

DeptClientServiceFallbackFactory实例如下:

@Component // 不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
  @Override
  public DeptClientService create(Throwable throwable)
  {
    return new DeptClientService() {
      @Override
      public Dept get(long id)
      {
        Dept dept = new Dept();
        dept.setDeptno(id);
        dept.setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭");
        dept.setDb_source("no this database in MySQL");
        return dept;
      }
      @Override
      public List<Dept> list()
      {
        return null;
      }
      @Override
      public boolean add(Dept dept)
      {
        return false;
      }
    };
  }
}

② 修改DeptClientService上的@FeignClient

@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService
{
  @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
  public Dept get(@PathVariable("id") long id);
  @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
  public List<Dept> list();
  @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
  public boolean add(Dept dept);
}

③ 修改/microservicecloud-consumer-dept-feign工程的yml

server:
  port: 80
spring:
  application:
    name: microservicecloud-consumer
feign:
  hystrix:
    enabled: true
eureka:
  instance:
    prefer-ip-address: true # 注册服务的时候使用服务的ip地址
  client:
    register-with-eureka: false # 不向服务注册中心注册自己
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  
#      defaultZone: http://localhost:7001/eureka/

④ 测试

首先启动三个服务中心7001 7002 7003,然后启动服务提供者/microservicecloud-provider-dept-8001,最后启动服务消费者/microservicecloud-consumer-dept-feign。

正常访问:http://localhost/consumer/dept/get/1


将服务提供者关掉,然后再测试消费者:

可以看到,此时我的服务提供者provider已经down了,但是我们做了服务降级处理,让客户端在服务不可用的时候也会获得信息提示而不会挂起耗死服务器。


【3】服务监控Hystrix Dashboard

除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续的记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户。其中包括每秒执行多少请求,多少成功,多少失败等。


Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。SpringCloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。


① 新建module microservicecloud-consumer-hystrix-dashboard

pom文件如下:

   <dependencies>
  <!-- 自己定义的api -->
  <dependency>
    <groupId>com.web.springcloud</groupId>
    <artifactId>microservicecloud-api</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!-- 修改后立即生效,热部署 -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>springloaded</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
  </dependency>
  <!-- Ribbon相关 -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
  </dependency>
  <!-- feign相关 -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
  </dependency>
  <!-- hystrix和 hystrix-dashboard相关 -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
  </dependency>
   </dependencies>

② yml文件如下

server:
  port: 9001

③ 主启动类如下:

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

④ 服务提供者8001 8002 8003添加监控依赖

    <!-- actuator监控信息完善 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

⑤ 启动/microservicecloud-consumer-hystrix-dashboard


别乱猜,这货不是熊,这是豪猪!!!


⑥ 启动三个服务中心和/microservicecloud-provider-dept-hystrix-8001

访问http://localhost:8001/hystrix.stream:

可以看到该页面在不断获取数据!!!


⑦ 使用Hystrix Dashboard监控

页面如下填写,分别是监控URL,延迟时间和自定义名字。


⑧ 如何查看?

一圈–实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。

实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化。流量越大该实心圆也就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。


曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。



多次刷新http://localhost:8001/dept/get/1请求,然后查看Hystrix Dashboard如下:

连续发出六次请求http://localhost:8001/dept/get/1,如下图:

参数详细说明如下:



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
存储 数据可视化 Java
基于MicrometerTracing门面和Zipkin实现集成springcloud2023的服务追踪
Sleuth将会停止维护,Sleuth最新版本也只支持springboot2。作为替代可以使用MicrometerTracing在微服务中作为服务追踪的工具。
87 1
|
2月前
|
消息中间件 存储 Java
SpringCloud基础9——服务异步通信-高级篇
消息可靠性、死信交换机、惰性队列、MQ集群
SpringCloud基础9——服务异步通信-高级篇
|
2月前
|
存储 NoSQL 调度
|
2月前
|
XML 监控 Java
Spring Cloud全解析:熔断之Hystrix简介
Hystrix 是由 Netflix 开源的延迟和容错库,用于提高分布式系统的弹性。它通过断路器模式、资源隔离、服务降级及限流等机制防止服务雪崩。Hystrix 基于命令模式,通过 `HystrixCommand` 封装对外部依赖的调用逻辑。断路器能在依赖服务故障时快速返回备选响应,避免长时间等待。此外,Hystrix 还提供了监控功能,能够实时监控运行指标和配置变化。依赖管理方面,可通过 `@EnableHystrix` 启用 Hystrix 支持,并配置全局或局部的降级策略。结合 Feign 可实现客户端的服务降级。
153 23
|
2月前
|
Java API 对象存储
微服务魔法启动!Spring Cloud与Netflix OSS联手,零基础也能创造服务奇迹!
这段内容介绍了如何使用Spring Cloud和Netflix OSS构建微服务架构。首先,基于Spring Boot创建项目并添加Spring Cloud依赖项。接着配置Eureka服务器实现服务发现,然后创建REST控制器作为API入口。为提高服务稳定性,利用Hystrix实现断路器模式。最后,在启动类中启用Eureka客户端功能。此外,还可集成其他Netflix OSS组件以增强系统功能。通过这些步骤,开发者可以更高效地构建稳定且可扩展的微服务系统。
50 1
|
缓存 运维 监控
微服务技术系列教程(22) - SpringCloud- 服务保护机制Hystrix
微服务技术系列教程(22) - SpringCloud- 服务保护机制Hystrix
105 0
|
5月前
springCloud之服务降级熔断Hystrix、OpenFeign
springCloud之服务降级熔断Hystrix、OpenFeign
310 0
|
6月前
|
监控 Java API
Spring cloud Hystrix 、Dashboard、API(zuul)相关报错
Spring cloud Hystrix 、Dashboard、API(zuul)相关报错
60 2
|
2月前
|
Java 对象存储 开发者
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
52 3
|
5月前
|
监控 Java UED
Java一分钟之-Spring Cloud Netflix Hystrix:容错管理
【6月更文挑战第9天】Spring Cloud Hystrix是用于微服务容错管理的库,通过断路器模式防止服务雪崩。本文介绍了Hystrix的基本概念,如断路器、线程隔离和fallback机制,并展示了如何快速上手,包括添加依赖、启用注解和编写Hystrix命令。此外,还讨论了常见问题(如断路器打开、资源泄漏和不当的Fallback策略)及其解决方案。通过自定义Hystrix指标监控,可以进一步优化系统性能。理解Hystrix工作原理并适时调整配置,对于构建健壮的微服务至关重要。
197 3
下一篇
无影云桌面