Hystrix服务熔断和服务降级

源码地址:https://gitee.com/peachtec/springcloud

分布式面临的问题

  复杂分布式体系结构中的应用程序有数十个依赖,每个依赖关系在某些时候将不可避免的失败

服务雪崩

  多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的"扇出",如果扇出的链路上的某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统的奔溃,即"雪崩效应"
  对于高流量的应用来说,单一的后端依赖可能会导致所有的服务器上的所有资源在几秒钟内饱和,比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用或系统

服务熔断

  熔断机制是对应雪崩效应的一种微服务链路保护机制
  当扇出链路的某个微服务不可用或者相应时间太长时,会进行服务降级,进而熔断该节点的微服务的调用,快速返回错误信的响应信息;当检测到该节点的微服务调用相应正常后恢复调用链路;在SpringCloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间的调用情况,当失败的调用达到一定的阈值时,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand

什么是Hystrix

  Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多的依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性
  "熔断器"本身是一种开关装置,当某个服务单元发生故障时,通过断路器的故障监控,向调用方返回一个服务预期的,可处理的备选相应,而不是长时间的等待或者抛出调用方法无处理的异常,这样就保证了服务调用方的线程不会被长时间不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩

Hystrix的作用

  1. 提供保护并控制通过第三方客户端库(通常是通过网络)访问的依赖项的延迟和失败。
  2. 停止复杂的分布式系统中的级联故障。
  3. 快速失败并快速恢复。
  4. 回退并在可能的情况下正常降级。
  5. 启用近乎实时的监视,警报和操作控制。

Hystrix解决什么问题

  复杂分布式体系结构中的应用程序具有数十种依赖关系,每种依赖关系不可避免地会在某个时刻失败。如果主机应用程序未与这些外部故障隔离开来,则可能会被淘汰。
  例如,对于依赖30个服务的应用程序,其中每个服务的正常运行时间为99.99%,您可以期望:

99.99 30 = 99.7%的正常运行时间
10亿个请求中的0.3%= 3,000,000个故障
/每月2小时以上的停机时间,即使所有依赖项都具有出色的正常运行时间。
  

  现实通常更糟。即使您没有对整个系统进行弹性设计,甚至所有依赖项都很好地执行,甚至0.01%的暂停时间对数十种服务中的每一项的总影响也等于每月可能停机数小时。
  当一切正常时,请求流如下所示:
在这里插入图片描述
  当众多依赖服务中有一个发送故障时,它可能会阻塞全部用户请求:
在这里插入图片描述
  随着高流量访问,单个后端服务发生错误,这可能导致所有服务器上的资源在短短几秒钟内变的饱和(并不是一定会造成资源饱和。例如,该故障请求返回超时,则可能造成线程数急剧增加,若请求不能即使释放,造成网络阻塞)。
  应用程序接受到请求,通过网络对每个依赖服务进行访问,这时每个服务都有可能存在潜在的错误。比起当个服务宕机,更可怕的是,这些服务可能导致服务之间的延迟增加,从而导致备份队列,线程和其他资源被占用,从而导致整个系统的级联故障(整个服务集群宕机,甚至造成服务器不可达)。
在这里插入图片描述

Hystrix的设计原则

  1. 防止单个依赖服务耗尽整个容器(例如:tomcat,jboss等)用户线程
  2. 减少负载并快速失败,而不是排队(之间断路,而不是等待恢复)。
  3. 在允许的情况下提供备用机制,保护用户免受故障影响。
  4. 使用隔离技术 (例如隔离, 泳道, 断路) 去限制一个依赖服务故障带来的影响
  5. 通过近实时指标,监视和警报优化发现时间
  通过在Hystrix的大多数方面中以低延迟传播配置更改来优化恢复时间,并支持动态属性更改,这使您可以通过低延迟反馈环路进行实时操作修改。
  6. 防止整个服务集群执行失败,而不仅仅是网络请求的失败(网络阻塞)。
  

Hystrix 如何实现其设计目标?

Hystrix 通过以下方式做到了这些:
  1. 将依赖服务(或者是依赖项)包装在一个单独线程执行的 HystrixCommand 或 HystrixObservableCommand 对象中执行(命令模式)。
  2. 请求超时花费的时间超过定义的阈值(配置的超时时间)。Hystrix提供一个超时配置,这个配置比实际的请求时间要略高一些,这些请求若发生超时,会直接拒绝请求(这里也是返回 超时异常的主要原因)。
  3. Hystrix 会维护一个小的线程池(或者信号量);如果信号量或者线程池已满,请求会直接被拒绝而不是等待或排队。
  4. 计算成功或失败 (通过Hystrix客户端抛出的异常), 超时, 和线程拒绝.
  5. 如果某个服务的发生错误的百分比超过阈值,则会触发断路器断路(跳闸)。在接线来的一段时间里会自动或者手动的停止特定请求(被执行断路的请求)。
  6. 对发生请求失败,请求拒绝,请求超时,或断路的请求执行 回退(Fallback)策略。
  7. 实时的监控和动态配置。
  当你使用Hystrix 封装依赖服务时,上图所示的情况的体系结构将会变为类似于下图的情况。每个依赖项彼此隔离(通过HystrixCommand 或 HystrixObservableCommand进行的隔离),当依赖项发生错误,超时,资源(线程,信号量)限制,或者拒绝都会执行回退逻辑。回退逻辑在依赖项发送任何类型的故障时都会做出相应。
在这里插入图片描述

服务熔断

  服务熔断是进行在服务提供者的,所以去改造一个服务提供者模块,为了方便我就直接在创建提个服务提供这模块,代码直接复制其他的服务提供者模块的代码,然后添加Hystrix相关的代码

  1. 导入Hystrix jar包依赖
<!-- hystrix-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 在控制层接口上添加熔断注解,指定要熔断的方法
    @GetMapping("/get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixGet")//指定服务熔断执行的方法
    private Dept get(@PathVariable("id") Integer id) {
    
    
        Dept dept = service.queryById(id);
        if (dept == null) {
    
    
            throw new RuntimeException("用户不存在");
        }
        return dept;
    }

    /**
     * 备选方法
     */
    private Dept hystrixGet(@PathVariable("id") Integer id) {
    
    
        return new Dept().setId(id)
                .setName("没用对应信息")
                .setDbSource("mysql中没有这个数据库");
    }
  1. 开启服务熔断
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到eureka
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker
public class Dept_Hystrix_8001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(Dept_Hystrix_8001.class, args);
    }
}
  1. 启动服务进行测试,可以到,不管怎么查询,都不会向以前那样,直接给出一个错误的页面,而现在错误的查询会调用服务熔断指定的方法
    在这里插入图片描述
服务降级

  服务降级是进行在服务消费方的,配置Feign更方便使用,所以直接改造公共模块中关于Feign服务层接口的方法

  1. 在公共模块编一个类实现FallbackFactory类,并重新create方法,重新的方法返回Feign的服务层接口类
@Component
public class ClientFallbackFactory implements FallbackFactory {
    
    
    @Override
    public ClientService create(Throwable throwable) {
    
    
        return new ClientService() {
    
    
            @Override
            public boolean addDept(Dept dept) {
    
    
                return false;
            }

            @Override
            public Dept queryById(Integer id) {
    
    
                return new Dept().setId(id).setName("服务已关闭").setDbSource("no database");//测试案例
            }

            @Override
            public List<Dept> queryAll() {
    
    
                return null;
            }
        };
    }
}
  1. 在Feign的服务层接口类中配置Feign的返回工厂的类型
@FeignClient(value = "SPRINGCLOUD-SERVER",fallbackFactory = ClientFallbackFactory.class)
@Component
public interface ClientService {
    
    
    @PostMapping("/dept/add")
    boolean addDept(Dept dept);

    @GetMapping("/dept/get/{id}")
    Dept queryById(@PathVariable("id") Integer id);

    @GetMapping("/dept/get")
    List<Dept> queryAll();
}
  1. 在Feign的消费者模块中的yaml配置文件中开启降级服务
# 开启降级服务
feign:
  hystrix:
    enabled: true
  1. 启动测试
    在这里插入图片描述
Dashboard流监控

  Hystrix和客户端有相关的操作,就可以去监控这些请求,而Dashboard就是一个监控页面来监控这些信息的

  1. 创建 “springcloud-consumer-hystrix-dashboard” 模块,这个模块就是Dashboard的监控页面,然后导入jar包
<dependencies>
  <!-- dashboard -->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
  </dependency>
  <!-- hystrix-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  </dependency>
  <!-- Ribbon -->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  </dependency>
  <!-- Eureka -->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
  <dependency>
      <groupId>org.peach</groupId>
      <artifactId>springcloudentity</artifactId>
      <version>1.0</version>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
  </dependency>
</dependencies>
  1. 配置yaml文件,先简单的体验一哈,配置端口
server:
  port: 9001
hystrix:
  dashboard:
    proxy-stream-allow-list: "*"
  1. 在启动类上开启监控
@SpringBootApplication
@EnableHystrixDashboard//开启监控
public class DeptConsumerDashboard_9001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(DeptConsumerDashboard_9001.class, args);
    }
}
  1. 保证每个服务提供者模块中有 “spring-boot-starter-actuator” 服务监控的依赖,然后启动测试,在浏览器中访问 http://localhost:9001/hystrix,可以看到Dashboard默认的页面
    在这里插入图片描述
  2. 现在Dashboard里面是空的,没有任何东西,接下来就往里面配置,在服务提供者模块中进行注册,并且在需要监控的接口上加上 “@HystrixCommand” 注解
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到eureka
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker
public class Dept_Hystrix_8001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(Dept_Hystrix_8001.class, args);
    }
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet() {
    
    
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}
  1. 启动服务进行测试,浏览器访问 http://localhost:8001/actuator/hystrix.stream,实际端口根据自己的服务来访问,可以看到,当服务启动后,访问地址一直在ping某个东西,类似于心跳,当访问被监控的接口,页面就会有一些数据,相当于发送了一个心跳包
    在这里插入图片描述
  2. 接下来访问Dashboard的地址,在页面去监控流,
    在这里插入图片描述
    进入监控页面,就可以看到监控的接口的状态信息了,当前是没有任何访问的
    在这里插入图片描述
    当我们访问接口时,监控信息也会发生改变
    在这里插入图片描述
    接下来就详细聊聊关于这个信息界面
      一圈
      实心圆:共有两种含义,通过颜色的变化代表实例的健康程度,绿色<黄色<橙色<红色 递减;通过实例的请求流量它的大小也会随之变化,流量越大,实心圆就越大,所以通过实心圆表示,就可以在大量的 实例中快速的发现故障实例和高压实例
    在这里插入图片描述
      一线
      曲线:记录2分钟以内流量的相对变化,可以通过它来观测流量的上升和下降趋势
    在这里插入图片描述
      其他
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45481406/article/details/110404439