SpringCloud(14) —— Hystrix:服务降级

在这里插入图片描述

  • 注意:上一篇博客讲的服务熔断只是Hystrix的一种作用,它还有很多作用,不要把它仅仅限制于做服务熔断,这篇博客就讲一讲通过Hystrix实现服务降级


1.什么是服务降级

  • ​服务降级是指当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务
  • ​资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双11活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等
  • ​服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用
  • ​降级的方式可以根据业务来,可以延迟服务,比如延迟给用户增加积分,只是放到一个缓存中,等服务平稳之后再执行 ;或者在粒度范围内关闭服务,比如关闭相关文章的推荐

在这里插入图片描述

  • 由上图可得,当某一时间内服务A的访问量暴增,而B和C的访问量较少,为了缓解A服务的压力,这时候需要B和C暂时关闭一些服务功能,去承担A的部分服务,从而为A分担压力,这就叫做服务降级

  • 服务降级需要考虑的问题

    • 那些服务是核心服务,哪些服务是非核心服务
    • 那些服务可以支持降级,那些服务不能支持降级,降级策略是什么
    • 除服务降级之外是否存在更复杂的业务放通场景,策略是什么?
  • 自动降级分类

    • 超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况
    • 失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况
    • 故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)
    • 限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)

2.入门案例

  • 上一篇博客中实现的服务熔断是消费者向服务提供者暴露的API发送请求的时候,服务崩溃的时候的容错机制,注意:服务熔断是发生在服务崩溃/报错的时候,所以服务熔断应该在服务提供者提供的服务中实现
  • 而服务降级是在某一时刻系统为了维持核心功能的稳定运行而暂时停止对于非核心功能的提供的容错机制;但是它是在服务提供者模块中实现还是消费者模块中实现呢?
  • 注意:如果我们在服务提供者上面实现,就意味着我们需要直接将整个服务关闭,在合适的时候再将它开启,那么在此期间所有消费者都将不能访问被服务降级的服务,并且我们关闭服务的办法很暴力,就是直接关闭服务器,但是服务降级的本意是要运行非核心功能的服务器在服务降级之后分担核心功能服务器的压力,向外提供核心功能服务,所以在服务提供者上面实现是不满足需求的
  • 那么我们就应该在消费者方面实现,即如果一个服务出现了服务降级,那么消费者模块就会再用户请求这个服务的时候直接在客户端返回我们已经准备好的服务降级信息,即根本就不会让客户端发送请求到服务器占用服务器的资源,而是直接在消费者model中就拦截请求并返回服务降级提示信息,这样做减轻了出现服务降级的时候服务器的压力/资源消耗
  • 实现步骤也很简单,只需要在springcould-api中的service同级目录下创建一个实现FallbackFactory接口的实现类DeptClientServiceFallbackFactory即可
  • 我们还是拿根据ID查询部门信息为例
    package com.thhh.springcould.service;
    
    import com.thhh.springcould.pojo.Dept;
    import feign.hystrix.FallbackFactory;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    //实现接口中的服务降级
    @Component
    public class DeptClientServiceFallbackFactory implements FallbackFactory {  //实现服务降级的类需要实现接口FallbackFactory,即失败回调工厂
        @Override
        public DeptClientService create(Throwable throwable) {
            return new DeptClientService() {
                @Override
                public Dept queryById(Long id) {
                    return new Dept()
                            .setDeptno(id)
                            .setDname("没有找到"+id+"对应的数据,当前该服务已经出现了服务降级,该服务已经关闭,请等待服务重启之后再试")
                            .setDb_source("没有对应的数据库");
                }
    
                @Override
                public List<Dept> queryAll() {
                    return null;
                }
    
                @Override
                public boolean addDept(Dept dept) {
                    return false;
                }
            };
        }
    }
    
  • 在实现服务熔断的时候为了指定某一个方法熔断之后顶替它的方法,我们使用了注解@HystrixCommand,并传入了参数fallbackMethod指定顶替方法名称
  • 实现服务降级的时候我们需要配合前面学习使用的Feign的注解@FeignClient和它的参数fallbackFactory,这个参数用于传入FallbackFactory接口的实现类,所以我们可以对学习Feign的时候创建的service接口上的注解@FeignClient进行改造,其实就是在它的注解中多传入一个参数fallbackFactory
    package com.thhh.springcould.service;
    
    import com.thhh.springcould.pojo.Dept;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;//@FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
    
    
    @Service
    @Component
    //@FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
    @FeignClient(value = "SPRINGCOULD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
    public interface DeptClientService {
    
        @GetMapping("/dept/queryById/{id}")
        Dept queryById(@PathVariable("id") Long id);
    
        @GetMapping("/dept/queryList")
        List<Dept> queryAll();
    
        @PostMapping("/dept/add")
        boolean addDept(Dept dept);
    }
    

在这里插入图片描述

  • 去使用Feign作为负载均衡的消费者的model中的配置文件中开启Hystrix的降级服务

    server:
      port: 9001
    #eureka配置
    eureka:
      client:
        register-with-eureka: false #表示不向eureka中注册自己,即表明自己是一个消费者
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #配置可以连接的eureka注册中心的url
    
    feign:
      hystrix:
        enabled: true	#只需要设置该属性就可以开启该消费者model的hystrix服务降级
    
  • 开启对应的model进行测试
    在这里插入图片描述
    在这里插入图片描述

  • 此时我们公司的服务遇到了洪流,需要将提供上面这个功能的服务器关闭对外的服务,转而去为遇到洪流的服务器分担压力,对于正常访问这个服务的消费者而言这台服务器就和关闭了没有什么区别,所以我们可以去IDEA中关闭该服务提供者
    在这里插入图片描述

  • 再次访问该服务
    在这里插入图片描述

  • 可见即使我们关闭了提供这个服务的服务器,消费者模块再次访问该服务API的时候,返回到前端的数据是一开始我们设置好的服务降级处理反馈的数据


3.小结

  • 通过上面的案例我们大致可以明白服务降级的作用,以及它的实现
  • 上面的例子在实现服务降级的时候只是在公用的数据model springcould-api中实现了接口FallbackFactory,实现的方法create()返回的数据类型为DeptClientService,即前面我们为了实现Feign定义的一个接口对象,但是接口不能直接new,所以我们就在方法create()中实现了接口DeptClientService,为每一个方法定义了服务降级之后再被访问的时候返回的数据
    @Component
    public class DeptClientServiceFallbackFactory implements FallbackFactory {  //实现服务降级的类需要实现接口FallbackFactory,即失败回调工厂
        @Override
        public DeptClientService create(Throwable throwable) {
            return new DeptClientService() {
                @Override
                public Dept queryById(Long id) {
                    return new Dept()
                            .setDeptno(id)
                            .setDname("没有找到"+id+"对应的数据,当前该服务已经出现了服务降级,该服务已经关闭,请等待服务重启之后再试")
                            .setDb_source("没有对应的数据库");
                }
    
                @Override
                public List<Dept> queryAll() {
                    return null;
                }
    
                @Override
                public boolean addDept(Dept dept) {
                    return false;
                }
            };
        }
    }
    

在这里插入图片描述

  • 然后我们就需要去需要去对应的这个接口的注解@FeignClient中传入参数fallbackFactory,值就是上面我们实现接口FallbackFactory的类的class对象
    @Service
    @Component
    //@FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
    @FeignClient(value = "SPRINGCOULD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
    public interface DeptClientService {
    
        @GetMapping("/dept/queryById/{id}")
        Dept queryById(@PathVariable("id") Long id);
    
        @GetMapping("/dept/queryList")
        List<Dept> queryAll();
    
        @PostMapping("/dept/add")
        boolean addDept(Dept dept);
    }
    
  • 最后就是去使用了Feign作为负载均衡的消费者模块中的配置文件开启hystrix的服务降级功能
    server:
      port: 9001
    #eureka配置
    eureka:
      client:
        register-with-eureka: false #表示不向eureka中注册自己,即表明自己是一个消费者
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #配置可以连接的eureka注册中心的url
    
    feign:
      hystrix:
        enabled: true
    

在这里插入图片描述

  • 在测试的流程中,在正常的情况下(开启了服务降级的消费者模块对应消费的服务提供者模块正常运行的情况下),消费者可以正常的通过Feign的接口方式对于服务进行消费,但是一旦提供该服务的服务器不再对外提供服务的时候,即我们在IDEA中关闭了这个微服务的时候,再次请求该微服务中提供的任何服务功能,返回的都是一开始在接口FallbackFactory中定义好的提示信息
  • 注意:整个实现流程中,我们并没有修改服务提供者的任何代码,只是在公共数据模块springcould-api中添加了一个实现接口FallbackFactory的类,在Feign接口的注解@FeignClient上添加了一个传入的参数,在使用Feign的消费者模块中开启了Hystrix的服务降级功能,然后就开启的服务进行了测试

4.对比服务熔断和服务降级

  • 服务熔断是发生在消费者已经向服务提供者提供的服务的API发送了请求数据,并在一连串的微服务调用中出现了某一个服务崩溃的时候,它防止了大量用户访问该崩溃服务造成的服务雪崩
  • 服务降级是发生在服务提供者为了满足核心功能的正常供应,将非核心功能提供的服务暂时关闭,而消费者此时又对非核心服务进行访问的时候,它防止因为当前非核心业务服务被停止供应而出现客户端异常的情况,并且在消费者模块中就对消费者对于服务的请求进行拦截,并返回定义好的服务降级的提示信息
    • 触发的条件就是我们使用的Feign不能关联到注册中心中指定的服务名称的服务,从而就会去调用fallbackFactory指定的失败回调工厂返回的DeptClientService对象中对应的方法返回服务降级提示信息
    • 即保证了服务器关闭之后服务将不再被调用,消费者还是可以正常的发送对应服务的请求,只是这个请求不会到达服务器,在消费者模块中自己的就进行了处理,并返回服务降级信息
    • 对于服务降级,它返回的是一个缺省值,整个系统提供的服务水平下降了,但是整个系统的核心业务还能正常提供,非核心业务也能正常的返回提示信息,比服务直接挂掉要强
  • 服务熔断是针对每一个方法进行的容灾手段;而服务降级是针对某一个Feign的服务接口的容灾手段,对比之下可见服务降级是对一系列服务API的容灾手段(就是一个服务者提供的所有服务API)
服务熔断:服务端~某个服务超时或者异常,引起熔断~,作用和保险丝类似~
服务降级:客户端~从整体网站请求负载考虑~,当某个服务熔断或者关闭之后,服务将不再被调用~
此时在客户端,我们可以准备一个FallbackFactory,返回一个默认的值(缺省值),整体的服务水平下降了~但是,好歹能用,比直接挂摊强
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值