4.微服务基础-服务熔断

服务熔断

1. 高并发问题

1.1. 问题说明

对于同一个微服务,其中有可多个接口,若其中某些接口接收到了大量的请求,超出了web容器(tomcat等)支持的最大并发线程数(tomcat会以线程池的形式对所有的请求进行统一的管理),并且响应时间很长,势必会造成这些请求的积压,当请求这个微服务中的其他接口时,会造成这部分的请求的等待,造成整个微服务的不可用。

1.2. 解决方案

为了同一个微服务中的一个接口不影响其他接口的正常访问,可以对多个服务之间进行隔离。

  1. 线程池隔离

    针对每个接口,配置一个线程池。

  2. 信号量隔离

    在系统中针对每个接口记录一个请求的最大阈值,当这个接口的请求数量超过这个阈值时便会进行报错,保证这个接口不会积压太多的请求。

2. Hystrix

2.1. 服务容错核心概念

  1. 雪崩效应

    在微服务架构中,多个服务之间的调用是非常常见的,若服务A调用服务B,服务B调用服务C,而由于某些原因,服务C迟迟不返回,请求一直积压,那么服务B和服务A就会一直处于等待的状态,服务B和服务A随着时间的推移,请求越积压越多,最后造成整个服务的不可用。

    雪崩是系统中的蝴蝶效应,导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一方法响应变慢,亦或是某台机器的资源耗尽,从源头上我们无法杜绝雪崩的发生,但雪崩的根本原因来自于服务之间的强依赖,所以我们可以提前评估,做好熔断、隔离、限流。

  2. 服务隔离

    顾名思义,服务隔离是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相互独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其他模块,不影响整体的系统服务。

  3. 熔断降级

    所谓熔断,是指在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用,这种牺牲局部,保全整体的措施就叫做熔断。

    所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时上游服务可以自己准备一个本地的Fallback回调,返回一个缺省值,也可以理解为兜底。

  4. 服务限流

    限流可以认为是服务降级的一种,限流就是限制系统的输入和输出流量以达到保护系统的目的,一般来说系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的,比如推迟解决、拒绝解决,或者部分拒绝解决等。

2.2. Hystrix介绍

Hystrix是由Nstflix开源的一个延迟和容错库(断路器),用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提升系统的可用性与容错性,Hystrix主要通过以下几点实现延迟和容错:

  • 包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行(设计模式中的命令模式)。
  • 跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或信号量),如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
  • 监控:Hystrix提供友好的页面监控控制台,可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态。

Hystrix不仅支持使用RestTemplate实现服务熔断,也支持使用Feign实现服务熔断。

2.3. Rest实现服务熔断

  1. 引入Hystix的依赖

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  2. 在启动类激活Hystix

    @EnableCircuitBreaker
    
  3. 配置熔断触发的降级逻辑

    /**
     * 自己定义熔断触发的降级方法
     * 方法的返回值必须和需要受到保护的方法的返回值保持一致
     * 方法的参数值也可以和需要受到保护的方法的参数值保持一致
     */
    public T tFallBack(String args) {
      T t = new T("触发熔断降级");
      return t;
    }
    
  4. 在需要受到保护的接口 ( Controller的方法 ) 上使用@HystixCommand配置

    /**
     * 使用@HystixCommand配置熔断保护
     * fallbackMethod : 配置熔断之后的降级方法名
     */
    @HystixCommand(fallbackMethod = "tFallBack")
    @RequestMapping(value = "/method/{args}", method = RequestMethod.GET)
    public T test(@Pathvariable String args) {
      return restTemplate.getForObject("http://service-name/method", T.class);
    }
    
  • 熔断超时设置

    Hystrix的默认超时时间为1秒,即访问下游微服务的超时时间,若超过超时时间没有获取到返回值,就会自动触发降级方法。可以通过配置来修改这个值:

    hystrix:
    	command:
    		default:
    			execution:
    				isolation:
    					thread:
    						timeoutInMilliseconds: 1000  #单位毫秒
    
  • 配置一个controller中统一的熔断降级方法

    在一个controller中会有很多的方法,如果对每一个方法都配置一个熔断降级方法,会显得很繁琐,Hystrix支持配置一个统一的熔断降级方法,针对这一个controller中的所有熔断保护的方法都可以执行这个统一的降级逻辑。

    /**
      * 使用@DefaultProperties配置统一的熔断设置
      * defaultFallBack : 配置熔断之后的统一降级方法名
      */
    @RestController
    @DefaultProperties(defaultFallBack = "defaultFallBack")
    public class TestController {
      
      @Autowried
      private RestTemplate restTemplate;
    
      /**
       * 使用@HystixCommand配置熔断保护
       * 使用统一的熔断降级方法,就不需要再指定fallbackMethod了
       */
      @HystixCommand
      @RequestMapping(value = "/method/{args}", method = RequestMethod.GET)
      public T test(@Pathvariable String args) {
        return restTemplate.getForObject("http://service-name/method", T.class);
      }
      
      /**
       * 自己定义统一的熔断触发的降级方法
       * 方法不可以有参数
       * 注意:如果要使用这个统一的熔断触发的降级方法,那么这个Controller中的熔断保护的方法的返回值应该一致
       */
      public T defaultFallBack() {
        T t = new T("触发统一的熔断降级");
        return t;
      }
    }
    

2.4. Feign实现服务熔断

  1. 引入依赖(Feign中已经集成了Hystix,所以只需要使用Feign的依赖就可以了)

  2. 在Feign中配置开启Hystrix

    feign:
    	hystrix:
    		enable: true
    
  3. 自定义一个接口的实现类,这个接口的实现类就是熔断触发的降级逻辑

    定义一个实现类,实现对应熔断保护的方法的FeignClient接口,并将这个类注入到Spring容器中

    @Component
    public class ProductFeignClientFallback implements ProductFeignClient {
      /**
       * 即熔断降级方法
       */
      @Override
      public Product findById(Long id) {
        return new Product("触发了熔断降级");
      }
    }
    
  4. 修改FeignClient接口,添加降级方法的支持

    /**
     * @FeignClient(name = "微服务名称") : 声明需要调用的服务提供者的服务名称
     * @FeignClient(fallback = 实现类.class) : 配置熔断发生的降级方法
     */
    @FeignClient(name = "service-product", fallback = ProductFeignClientFallback.class)
    public interface ProductFeignClient {
      /**
       * 配置需要调用的服务提供者的接口,支持SpringMVC的方式
       * @RequestMapping(value = "接口请求路径")
       */
      @RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
      public Product findById(@PathVariable("id") Long id);
    }
    

2.5. Hystrix的监控平台

  1. 使用Spring Boot Actuator 查看Hystrix实时的监控信息

    Hystrix会自动生成很多的监控信息,这些监控信息会暴露在Spring Boot的Actuator提供的/health端点中,帮助Hystrix整理收集并且输出的,所以我们需要为项目添加Spring-boot-actuator依赖后,并在启动类激活Hystrix,访问http://ip:port/actuator/hystrix.stream,即可看到实时的监控信息。

    # 配置Actuator,暴露所有端点
    management:
    	endpoints:
    		web:
    			exposure:
    				include: '*'
    

    使用Spring Boot Actuator 查看到的Hystrix实时的监控信息,是一堆流式的数据,并不利于直接观察。

  2. Hystrix DashBoard监控

    Hystrix官方提供了基于图形化的DashBoard(仪表板)监控平台,Hystrix DashBoard可以显示每个断路器(被@HystrixCommand注解的方法)的状态。

    • 导入依赖

      <dependency>
      	<groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
      	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      </dependency>
      <dependency>
      	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
      </dependency>
      
    • 启动类添加@EnableHystrixDashboard注解,激活仪表盘项目

    • 访问测试

      访问地址为http://ip:port/hystrix,在此页面中需要配置Spring Boot Actuator打印Hystrix实时的监控信息的访问地址:http://ip:port/actuator/hystrix.stream

    在微服务体系结构中,每个微服务都需要配置Hystrix DashBoard监控,每次只能查看单个实例的监控数据,这显然不是很方便的。

  3. Hystrix Turbine断路器聚合监控

    引入Turbine后,整个监控系统架构如下:

    • 搭建Turbine Server微服务,引入相关依赖

      <dependency>
      	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
      </dependency>
      <dependency>
      	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      </dependency>
      <dependency>
      	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
      </dependency>
      
    • 配置多个微服务的Hystrix监控

      turbine:
      	appConfig: service-1,service-2 #监控的微服务名称列表,多个用逗号隔开
      	clusterNameExpression: "'default'"
      
    • 启动类上使用@EnableHystrixDashboard注解开启Dashboard监控平台,并使用@EnableTurbine注解激活Turbine

    • 访问测试

      访问地址为http://ip:port/hystrix,在此页面中需要配置Spring Boot Actuator打印Hystrix实时的监控信息的访问地址:http://ip:port/turbine.stream

2.6. 断路器的状态

  1. Hystrix可以对请求失败的请求、被拒绝的请求或者请求超时的请求,进行统一的降级处理。

  2. 断路器的状态

    断路器(熔断器)默认为关闭CLOSED状态,当触发熔断后状态变更为OPEN,再等待到指定的时间,Hystrix会请求检测服务是否开启,这期间断路器会变为HALF_OPEN半开启状态,断路器探测到服务可用则继续变更为CLOSED关闭断路器。

    • CLOSED:关闭状态,所有的请求都可以正常访问。
    • OPEN:开启状态,所有的请求会进入到降级方法(Hystrix默认请求次数大于20次/10秒,且存在50%的失败概率就会触发开启状态)
    • HALF_OPEN:半开启状态,维持OPEN状态一段时间(Hystrix默认5秒),进入半开状态(尝试释放一个请求到远程微服务发起调用),如果释放的请求可以正常访问,就会关闭断路器;如果释放的请求不能正常访问,则继续保持开启状态5秒。

    修改断路器设置的默认参数:

    hystrix:
    	command:
    		default:
    			circuitBreaker:
    				requestVolumeThreshold: 20 #触发熔断的最小请求次数,默认20次/10秒
    				errorThresholdPrecentage: 50 #触发熔断的失败请求最小占比,默认50%
    				sleepWindowInMilliseconds: 5000 #熔断多少秒后尝试请求,默认5秒
    

2.7. 断路器的隔离策略

  1. 线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求做处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流浪洪峰来临时,处理不完可将数据存储到线程池队列里慢慢处理)。

  2. 信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来时先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作:请求来计数器+1、请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。

    功能线程池隔离信号量隔离
    线程与调用线程非相同线程与调用线程相同(jetty线程)
    开销排队、调度、上下文开销等无线程切换、开销低
    异步支持不支持
    并发支持支持(最大线程大小)支持(最大信号量上限)

隔离策略相关配置:

hystrix:
	command:
		default:
			execution:
				isolation:
					strategy: ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
					strategy: ExecutionIsolationStrategy.THREAD #线程池隔离
					maxConcurrentRequests: 100 #最大信号量上限

2.8. Hystrix源码解析

Hystrix的底层基于RxJava,RxJava是响应式编程开发库,因此Hystrix的整个实现策略简单来说,即:把一个HystrixCommand封装成一个Observable(待观察者),针对自身要实现的核心功能,对Observable进行各种修饰,并在订阅各步修饰的Observable,以便在指定事件达到时,添加自己的业务。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值