SpringCloud(22)之Sentinel实战应用

一、Sentinel核心库

        sentinel主页:主页 · alibaba/Sentinel Wiki · GitHub

1.1 Sentinel介绍 

         随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

1)Sentinel核心组件

1:核心库(Java 客户端 不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同 时对 Dubbo / Spring Cloud 等框架也有较好的支持。

2:控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

2)Sentinel VS Hystrix 

对比内容

Sentinel

Hystrix

隔离策略

信号量隔离

线程池隔离/信号量隔离

熔断降级策略

基于响应时间或失败比率

基于失败比率

实时指标实现

滑动窗口

滑动窗口(基于 RxJava

规则配置

支持多种数据源

支持多种数据源

扩展性

多个扩展点

插件的形式

基于注解的支 持

支持

支持

限流

基于 QPS,支持基于调用关系的限流

不支持

流量整形

支持慢启动、匀速器模式

不支持

系统负载保护

支持

不支持

控制台

开箱即用,可配置规则、查看秒级监控、机器 发现等

不完善

常见框架的适 配

ServletSpring Cloud DubbogRPC 

ServletSpring Cloud

Netflix

3)Sentinel概念 

  • 资源:资源是Sentinel的关键概念,他可以是Java应用程序的任何内容,例如,由应用程序提供的服务,或由应用程序调用其他服务提供的服务,甚至可以是一段代码; 只要通过Sentinel API定义的代码,就是资源,能够被Sentinel保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源来标示资源。
  • 规则:围绕资源的实时状态设定的规则,可以包括流量控制规则,熔断规则以及系统保护规则,所有规则可以动态实时调整。

1.2 Sentinel核心功能

 1.2.1 流量控制

        流量控制在网络传输中是一个常用的概念,他用于调整网络包的发送数据,然而,从系统的稳定性角度考虑,也有非常多的讲究。在任意时刻到来的请求往往是随机不可控的,而系统的处理能力有限,我们需要根据系统的的处理能力对流量进行控制.Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

流量控制设计理念 

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如:QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等;

        Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

1.2.2 熔断降级

        除了流量控制之外,及时对调用链路中的不稳定因素进行熔断也是Sentinel的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求堆积,进而导致级联故障。

 

        Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

 1)Sentinel熔断设计理念

        Hystrix通过线程池隔离的方式,来对依赖进行了隔离,这样做的好处就是资源和资源之间 做到了最彻底的隔离。缺点就是增加了线程切换的成本,还要先给各个资源做线程池大小的分配。

        Sentinel对这个问题采取了两种手段:

  • 通过并发线程数进行控制

        和资源池隔离的方法不同,Sentinel通过限制资源并发线程的数量,来减少不稳定资源对其他资源的影响。也不需要预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间过长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源商堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才会开始继续处理请求。

  • 通过响应时间对资源进行降级

        除了对并发线程数进行控制外,Sentinel还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会直接被拒绝,直到过了指定时间的窗口后才恢复。

2)系统自适应保护

        Sentinel同时提供系统维度的自适应能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统奔溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其他机器上,如果这个时候其他的机器也处于一个边缘状态,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。

        针对这个情况,Sentinel提供了对应的保护机制,让系统的入口流量和系统负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

1.3 Sentinel熔断限流

         Sentinel可以简单的分为Sentinel核心库和Dashboard。核心库不依赖Dashboard,但是结合Dashboard可以取得最后的效果。我们先来学习一下Sentinel核心库的使用。后面在学习Dashboard的使用。

        在我们项目中,用户请求通过 hailtaxi-gateway路由到 hailtaxi-driver 或者 hailtaxi-order ,还 有可能在 hailtaxi-order 中使用feign调用 hailtaxi-driver ,所以我们有可能在单个服务中实现熔   断限流,也有可能要集成feign调用实现熔断限流,还有可能在微服务网关中实现熔断限流。我们接下   来一步一步实现每一种熔断限流操作。 

1.3.1 Springboot集成

        如果在Springboot项目中集成,首先需要引入依赖,并使用@SentinelResource标记资源。

 1.3.1.1 @SentinelResource注解

         @SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。

        @SentinelResource 注解包含以下属性:

value

资源名称,必需项(不能为空)

blockHandler /

blockHandlerClass

blockHandler 对应处理 BlockException 的函数名称,可选项。    blockHandler 函数访问范围需要是 public 返回类型需要与原  方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的 参数,类型为 BlockException  blockHandler 函数默认需要和 原方法在同一个类中。若希望使用其他类的函数,则可以指定

blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必 需为 static 函数,否则无法解析。

fallback / fallbackClass

fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback

处理逻辑。fallback 函数可以针对所有类型的异常(除了

exceptionsToIgnore 里面排除掉的异常类型)进行处理。  fallback 函数签名和位置要求:  返回值类型必须与原函数返回值类型一

致; 方法参数列表需要和原函数一致,或者可以额外多一个

Throwable 类型的参数用于接收对应的异常。   fallback 函数默认 需要和原方法在同一个类中。若希望使用其他类的函数,则可以指  fallbackClass 为对应的类的 Class 对象,注意对应的函数必需    static 函数,否则无法解析。

defaultFallback(1.6.0  )

默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑 (即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类   型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处 理。若同时配置了 fallback defaultFallback,则只有 fallback     会生效。  defaultFallback 函数签名要求:  返回值类型必须与原   函数返回值类型一致; 方法参数列表需要为空,或者可以额外多 一个 Throwable 类型的参数用于接收对应的异常。   

defaultFallback 函数默认需要和原方法在同一个类中。若希望使用 其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 

象,注意对应的函数必需为 static 函数,否则无法解析。

exceptionsToIgnore(1.6.0 开始)

用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

entryType

entry 类型,可选项(默认为 EntryType.OUT)

1.3.1.2 blockHandler

        在对应的模块中加入依赖:

        <!--sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        我们为 info()方法添加一个 @SentinelResource注解,用来标注资源,表示当前方法需要执行限流、降级,在注解中添加value属性,用来标注资源,说白了就是给当前资源起个名字,blockHandler  用来表示当前方法发生 BlockException异常的时候,将处理流程交给指定的方法 blockExHandler() 处理,此时 blockExHandler()方法必须和抛出异常的方法在同一个类中,这是一种降级操作,代码如   下:

    @SentinelResource(value = "info",blockHandler = "blockExHandler")
    public Driver info(@PathVariable(value = "id")String id) throws InterruptedException{
        Driver driver = driverService.findById(id);
        //if(id.equals("1")){
        //    TimeUnit.SECONDS.sleep(10);
        //}
        if(driver==null){
            //throw new RuntimeException("司机不存在");
            throw new SystemBlockException("info","hailtaxi-driver");//必须抛出BlockException才会生效
        }
        driver.setName(driver.getName()+",IP="+ip);
        return driver;
    }

    /***
     * BlockException异常处理
     */
    public Driver blockExHandler(String id,BlockException ex){
        Driver driver = new Driver();
        driver.setId(id);
        driver.setName("bbb");
        return driver;
    }

        如果访问一个没有的数据就会报错异常,此时就会走blockhandler里面的逻辑。

1.3.1.3 fallback使用 

         如果我们希望抛出任何异常都能处理,都能调用默认处理方法,而并非只是 BlockException异常才调 用,此时可以使用 @SentinelResource  fallback属性,代码如下:

    @SentinelResource(value = "info",fallback ="exHandler")
    public Driver info(@PathVariable(value = "id")String id) throws InterruptedException{
        Driver driver = driverService.findById(id);
        //if(id.equals("1")){
        //    TimeUnit.SECONDS.sleep(10);
        //}
        if(driver==null){
            throw new RuntimeException("司机不存在");
//            throw new SystemBlockException("info","hailtaxi-driver");//必须抛出BlockException才会生效
        }
        driver.setName(driver.getName()+",IP="+ip);
        return driver;
    }

    /***
     * 异常处理
     */
    public Driver exHandler(String id){
        Driver driver = new Driver();
        driver.setId(id);
        driver.setName("aaa");
        return driver;
    }

         访问 http://localhost:18081/driver/info/3 测试出错效果如下:

        如果我们处理异常逻辑跟原方法不在同一个类中,可以使用@SentinelResource注解的fallbackclass实现,代码如下:

@SentinelResource(value = "info",fallback ="exHandler" ,fallbackClass ="xx.xxx.xxx.xx.Xxx")
 1.3.1.4 defaultFallback

         上面无论是 blockHandler还是 fallback ,每个方法发生异常,都要为方法独立创建一个处理异常的   方法,效率非常低,我们可以使用 @SentinelResource注解的 defaultFallback属性,为一个类指定 一个全局的处理错误的方法,代码如下:

@RestController
@RequestMapping(value = "/driver")
@RefreshScope
@SentinelResource(defaultFallback ="defaultExFallback")
public class DriverController {

    /***
     * 异常处理
     */
    public Driver defaultExFallback() {
        Driver driver = new Driver();
        driver.setName("系统繁忙,请稍后再试!");
        return driver;
    }
}

         此时需要注意,  defaultFallback属性指定的方法入参必须为空,最多可以增加一个异常对象。我们访问 http://localhost:18081/driver/info/3 效果如下:

1.3.2 限流规则 

         Sentinel支持多种限流规则,规则我们可以在代码中直接定义,规则属性如下:

Field

说明

默认值

resource

资源名,资源名是限流规则的作用对象

count

限流阈值

grade

限流阈值类型,QPS 模式(1)或并发线程数模式  0

QPS 模式

limitApp

流控针对的调用来源

default ,代表不区 分调用来源

strategy

调用关系限流策略:直接、链路、关联

根据资源本身(直

接)

controlBehavior

流控效果(直接拒绝/WarmUp/匀速+排队等 ),不支持按调用关系限流

直接拒绝

clusterMode

是否集群限流

1.3.2.1 流量控制 

         理解上面规则的定义之后,我们可以通过调用  FlowRuleManager.loadRules() 方法来用硬编码的方 式定义流量控制规则。

1)QPS流量控制

         我们先实现流量基于QPS控制,在 hailtaxi-driver  DriverApplication启动类上添加如下方法加 载限流规则,当 DriverApplication初始化完成之后加载规则,代码如下:

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(basePackages = "com.xxxxx.driver.mapper")
@EnableAutoDataSourceProxy
public class DriverApplication {

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext applicationContext = SpringApplication.run(DriverApplication.class,args);
    }

    /***
     * 初始化规则
     */
    @PostConstruct
    private void initFlowQpsRule() {
        //规则集合
        List<FlowRule> rules = new ArrayList<FlowRule>();
        //定义一个规则
        FlowRule rule = new FlowRule("info");
        // 设置阈值
        rule.setCount(2);
        //设置限流阈值类型
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS控制
//        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//线程数控制
        //default,代表不区分调用来源
        rule.setLimitApp("default");
        //将定义的规则添加到集合中
        rules.add(rule);
        //加载规则
        FlowRuleManager.loadRules(rules);
    }
}

        我们访问 http://localhost:18081/driver/info/1此时不会抛出异常,但是频繁刷新,则会调用降 级方法,效果如下: 

2)线程数流量控制 

         我们修改限流阈值类型,代码如下:

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(basePackages = "com.xxxxx.driver.mapper")
@EnableAutoDataSourceProxy
public class DriverApplication {

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext applicationContext = SpringApplication.run(DriverApplication.class,args);
    }

    /***
     * 初始化规则
     */
    @PostConstruct
    private void initFlowQpsRule() {
        //规则集合
        List<FlowRule> rules = new ArrayList<FlowRule>();
        //定义一个规则
        FlowRule rule = new FlowRule("info");
        // 设置阈值
        rule.setCount(2);
        //设置限流阈值类型
        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//线程数控制
        //default,代表不区分调用来源
        rule.setLimitApp("default");
        //将定义的规则添加到集合中
        rules.add(rule);
        //加载规则
        FlowRuleManager.loadRules(rules);
    }
}

         此时再来访问 http://localhost:18081/driver/info/1我们发现用浏览器无论怎么访问都不会出现 降级现象,但是如果用Jmeter模拟多个线程,效果就不一样了,效果如下:

 1.3.2.2 熔断降级

         熔断降级规则包含下面几个重要的属性:

Field

说明

默认

resource

资源名,即规则的作用对象

grade

熔断策略,支持慢调用比例/异常比例/异常数策略

慢调

用比

count

慢调用比例模式下为慢调用临界 RT(超出该值计为慢调 );异常比例/异常数模式下为对应的阈值

timeWindow

熔断时长,单位为 s

minRequestAmount

熔断触发的最小请求数,请求数小于该值时即使异常比率超出 阈值也不会熔断(1.7.0 引入)

5

statIntervalMs

统计时长(单位为 ms ), 60*1000 代表分钟级(1.8.0  入)

1000

ms

slowRatioThreshold

慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

         同一个资源可以同时有多个降级规则。理解上面规则的定义之后,我们可以通过调用 DegradeRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则,在  DriverApplication 规则定义如下:

    /***
     * 熔断降级规则
     */
    @PostConstruct
    private void initDegradeRule() {
        //降级规则集合
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        //降级规则对象
        DegradeRule rule = new DegradeRule();
        //设置资源
        rule.setResource("info");
        //设置触发降级阈值
        rule.setCount(2);
        /**
         * 熔断降级策略,支持慢调用比例/异常比例/异常数策略
         * DEGRADE_GRADE_RT:平均响应时间
         * DEGRADE_GRADE_EXCEPTION_RATIO:异常比例数量
         * DEGRADE_GRADE_EXCEPTION_COUNT:异常数
         */
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        //熔断窗口时长,单位为 s
        rule.setTimeWindow(10);
        //将规则添加到集合中
        rules.add(rule);
        //加载规则
        DegradeRuleManager.loadRules(rules);
    }
 1.3.2.3 系统自我保护

         Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 LoadCPU 使用率、总体 平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量 和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

        系统规则包含下面几个重要的属性:

Field

说明

默认值

highestSystemLoad

load1 触发值,用于触发自适应控制阶段

-1 (不生效)

avgRt

所有入口流量的平均响应时间

-1 (不生效)

maxThread

入口流量的最大并发数

-1 (不生效)

qps

所有入口资源的 QPS

-1 (不生效)

highestCpuUsage

当前系统的 CPU 使用率(0.0-1.0

-1 (不生效)

         理解上面规则的定义之后,我们可以通过调用 SystemRuleManager.loadRules() 方法来用硬编码的 方式定义流量控制规则。

    /***
     * 系统自我保护
     */
    //@PostConstruct
    private void initSystemRule() {
        //系统自我保护集合
        List<SystemRule> rules = new ArrayList<>();
        //创建系统自我保护规则
        SystemRule rule = new SystemRule();
        //CPU使用率 值为0-1,-1 (不生效)
        rule.setHighestCpuUsage(0.2);
        //所有入口资源的 QPS,-1 (不生效)
        rule.setQps(10);
        //入口流量的最大并发数,-1 (不生效)
        rule.setMaxThread(5);
        //所有入口流量的平均响应时间,单位:秒,-1 (不生效)
        rule.setAvgRt(5);
        //load1 触发值,用于触发自适应控制阶段,系统最高负载,建议取值 CPU cores * 2.5
        rule.setHighestSystemLoad(20);
        //将规则加入到集合
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }
1.3.2.4 热点数据 

         何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K  据,并对其访问进行限制。比如:

1:商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制

2:用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

         热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调 用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效.

         Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点 参数限流支持集群模式。

        要使用热点参数限流功能,需要引入以下依赖:

        <!--热点参数-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>1.8.1</version>
        </dependency>

        然后为对应的资源配置热点参数限流规则,并在 entry  的时候传入相应的参数,即可使热点参数限流 生效。

         热点参数规则(  ParamFlowRule  )类似于流量控制规则(  FlowRule ):

属性

说明

默认值

resource

资源名,必填

count

限流阈值,必填

grade

限流模式

QPS  

durationInSec

统计窗口时间长度(单位为秒),1.6.0 版本开始支持

1s

controlBehavior

流控效果(支持快速失败和匀速排队模式),1.6.0 版本开 始支持

快速失

maxQueueingTimeMs

最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本 开始支持

0ms

paramIdx

热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置

paramFlowItemList

参数例外项,可以针对指定的参数值单独设置限流阈值, 不受前面 count 阈值的限制。  仅支持基本类型和字符串  类型

         我们可以对热门参数比如下标为0的参数流量进行控制,对热点数据执行特殊限流,比如参数值为 tj  时候执行限流,在 DriverApplication 中创建限流配置,代码如下:

    /***
     * 热点参数初始化
     */
    @PostConstruct
    private static void initParamFlowRules() {
        ParamFlowRule rule = new ParamFlowRule("search")
                //参数下标为0
                .setParamIdx(0)
                //限流模式为QPS
                .setGrade(RuleConstant.FLOW_GRADE_QPS)
                //统计窗口时间长度(单位为秒)
                .setDurationInSec(10)

                /**
                 * 流控效果(支持快速失败和匀速排队模式)
                 * CONTROL_BEHAVIOR_DEFAULT:限流行为,直接拒绝
                 * CONTROL_BEHAVIOR_WARM_UP:限流行为,匀速排队 冷启动
                 * CONTROL_BEHAVIOR_RATE_LIMITER:限流行为,匀速排队
                 */
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
                //最大排队等待时长(仅在匀速排队模式生效  CONTROL_BEHAVIOR_RATE_LIMITER)
                //.setMaxQueueingTimeMs(600)
                //最大阈值为5
                .setCount(5);

        // 为特定参数单独设置阈值.
        //如下配置:当下标为0的参数值为tj的时候,阈值到达2的时候则执行限流
        ParamFlowItem item = new ParamFlowItem()
                //参数类型为int类型
                .setClassType(String.class.getName())
                //设置阈值为2
                .setCount(2)
                //需要统计的值
                .setObject(String.valueOf("tj"));
        rule.setParamFlowItemList(Collections.singletonList(item));
        //加载热点数据
        ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
    }

1.3  Sentinel对OpenFeign支持 

         Sentinel 适配了 Feign 组件。如果想使用,除了引入  spring-cloud-starter-alibaba-sentinel 的依 赖外还需要 2 个步骤:

1:配置文件打开 Sentinel  Feign 的支持:feign.sentinel.enabled=true

2:加入 spring-cloud-starter-openfeign 依赖使 Sentinel starter 中的自动化配置类生效

1)引入依赖 

        <!--sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.5.RELEASE</version>
        </dependency>

        <!--Openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

 2)还需要在Feign调用客户端中开启Feign的支持

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
      min-request-size: 2048 # 设置触发压缩的大小下限
      #以上数据类型,压缩大小下限均为默认值
    response:
      enabled: true # 开启响应压缩
  #开启Sentinel对Feign的支持
  sentinel:
    enabled: true

 1.3.1 fallback

         我们可以为Feign接口创建一个实现类,在实现类中处理程序异常降级处理方法,代码如下:

@Component
public class DriverFeignFallback implements DriverFeign {

    /**
     * status()降级处理方法
     */
    @Override
    public Driver status(String id, Integer status) {
        Driver driver = new Driver();
        driver.setId(id);
        driver.setStatus(status);
        driver.setName("系统比较繁忙,请您稍后再试!");
        return driver;
    }
}

         我们还需要在Feign接口上添加 fallback属性指定讲解处理的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallback = DriverFeignFallback.class)

1.3.2 fallbackFactory 

        我们可以为Feign接口创建一个降级处理的工厂对象,在工厂对象中处理程序异常降级处理方法,代码 如下:

@Component
public class DriverFeignFallbackFactory implements FallbackFactory<DriverFeign> {

    @Override
    public DriverFeign create(Throwable throwable) {
        return new DriverFeign() {

            /**
             * status()降级处理方法
             */
            @Override
            public Driver status(String id, Integer status) {
                Driver driver = new Driver();
                driver.setId(id);
                driver.setStatus(status);
                driver.setName("系统比较繁忙,请您稍后再试!");
                return driver;
            }
        };
    }
}

         我们还需要在Feign接口上添加 fallbackFactory属性指定讲解处理的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallbackFactory =
DriverFeignFallbackFactory.class)

         此时我们测试,效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466007.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言大小写字母的转换

通过ascll码表我们可以知道大写字母与小写字母相差32个数&#xff08;小写字母比大写字母大&#xff09;。因此&#xff0c;通过相加减32即可转换大小写字母。 #include <stdio.h>int main() {char ch c;char CH A;printf("%c\n", ch - 32);printf("%c…

《LeetCode热题100》笔记题解思路技巧优化_Part_4

《LeetCode热题100》笔记&题解&思路&技巧&优化_Part_4 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题二叉树&#x1f7e2;1. 二叉树的中序遍历&#x1f7e2;2.…

zookeeper集群安装部署和集群异常处理

准备jdk和zookeeper安装包【官网即可下载】 zookeeper-3.5.1-alpha.tar.gz jdk1.7.0_8020200612.tar 准备三台linux虚拟机【具体以项目实际需要为准】&#xff0c;并安装jdk和zookeeper 虚拟机地址如下&#xff1a;194.1.1.86&#xff08;server.1&#xff09;、194.1.1.74…

MacOS本地使用Docker Desktop 搭建Minio容器

1. 下载docker Desktop docker官网&#xff1a;https://www.docker.com/products/docker-desktop/ 根据自己的型号进行选择&#xff0c;我的M系列芯片&#xff0c;选择的是Apple-Chip&#xff0c;记得需要看到最后噢&#xff01; 最后有坑点解决办法&#xff01; 最后有坑点解…

聚类分析 | Matlab实现基于PCA+DBO+K-means的数据聚类可视化

聚类分析 | Matlab实现基于PCADBOK-means的数据聚类可视化 目录 聚类分析 | Matlab实现基于PCADBOK-means的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 PCA&#xff08;主成分分析&#xff09;、DBO&#xff08;蜣螂优化算法&#xff09;和K-means聚类…

安科瑞智慧安全用电云平台【无人化数据监控 远程控制 运维管理】

背景 在住宅火灾中&#xff0c;电气引发的居高不下&#xff0c;已查明原因的火灾中有52%系电气原因引起&#xff0c;尤其是各类家用电器、电动车、电气线路等引发的火灾越来越突出&#xff0c;仅电动自行车引发的较大火灾就有7起。这些事故暴露出电器产品生产质量、流通销售&a…

【Web】浅聊Hessian反序列化之Resin的打法——远程类加载

目录 前言 原理分析 XString&#xff1a;触发恶意类toString QName的设计理念&#xff1f; 远程恶意类加载Context&#xff1a;ContinuationContext QName&#xff1a;恶意toString利用 hash相等构造 EXP 前言 精神状态有点糟糕&#xff0c;随便学一下吧 首先明确一个…

解决Could not autowire. No beans of ‘UserMapper‘ type found问题

问题&#xff1a; 解决方法1 降低spring版本 失败 解决方法2 查看数据库连接&#xff0c;无作用 解决方法3 polo&#xff0c;Mapper不在同一级&#xff0c;修改&#xff0c;但无作用 解决方法4 将Autowrited改为Autowrited(required false)&#xff0c;无作用 解决方法…

嵌入式学习-网络编程

1.网络编程作用 程序能够通过网络与其他计算机上的程序进行数据交换、通信和协作 2.关键概念 两个对象&#xff1a;服务器&#xff08;被动响应请求&#xff09;&#xff0c;客户端&#xff08;主动发起请求&#xff09;。浏览器看b站视频时&#xff0c;浏览器就是客户端&am…

基于springboot创建mybatis

第一步&#xff1a;创建项目 第二步&#xff1a;添加依赖 第三步&#xff1a;连接MySQL 第四步&#xff1a;添加MySQL配置 #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://localhost:3306/myb…

cmake指定不同版本的mingw编译

cmake指定不同版本的mingw编译&#xff0c;实现思路&#xff1a; 通过指定编译链的方式实现即可。 案例如下&#xff1a; mingw530的archi686&#xff0c;mingw810的archx86_64&#xff0c;通过指定不同版本的mingw编译链&#xff0c;实现程序的32bit和64bit的编译。 # 使用mi…

【爬虫】– 抓取原创力文档数据

使用RPA工具&#xff0c;实现针对于原创力中不可下载文档的抓取&#xff0c;可延用于其他类似文库 1 使用工具、环境 影刀RPA、WPS Office、谷歌浏览器&#xff08;非指定&#xff09; 2 代码流程 3 关键点 此方案只适合抓取非VIP即可预览全文的文档&#xff0c;抓取下来的数…

程序人生——Java异常使用建议

目录 引出异常建议110&#xff1a;提倡异常封装&#xff1b;建议111&#xff1a;采用异常链传递异常 建议112&#xff1a;受检异常尽可能转化为非受检异常建议113&#xff1a;不要在finally块中处理返回值 建议114&#xff1a;不要在构造函数中抛异常建议115&#xff1a;使用Th…

镜像制作实战篇

“ 在失控边缘冲杀为&#xff0c;最终解脱” CMD与EntryPoint实战 EntryPoint 与 CMD都是docker 镜像制作中的一条命令&#xff0c;它们在概念上可能有些相似&#xff0c;但在使用中&#xff0c;两者是有明显的区别的。比如&#xff0c;执行一个没有调用EntryPoint、CMD的容器会…

Linux系统部署DolphinScheduler任务调度系统并实现无公网IP远程访问

文章目录 前言1. 安装部署DolphinScheduler1.1 启动服务 2. 登录DolphinScheduler界面3. 安装内网穿透工具4. 配置Dolphin Scheduler公网地址5. 固定DolphinScheduler公网地址 前言 本篇教程和大家分享一下DolphinScheduler的安装部署及如何实现公网远程访问&#xff0c;结合内…

常用加密算法解析

对称加密算法 所谓对称&#xff0c;就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则&#xff0c;规定如何进行加密和解密。 分类 常用的算法有&#xff1a;DES、3DES、AES等。 DES 全称为Data Encryption…

代码随想录阅读笔记-字符串【替换数字】

题目 给定一个字符串 s&#xff0c;它包含小写字母和数字字符&#xff0c;请编写一个函数&#xff0c;将字符串中的字母字符保持不变&#xff0c;而将每个数字字符替换为number。 例如&#xff0c;对于输入字符串 "a1b2c3"&#xff0c;函数应该将其转换为 "anu…

地下电缆频繁被挖断!智能地钉保卫电缆不马虎

随着城市规模的不断扩大和环境美化的高需求&#xff0c;越来越多管道线路转战地下&#xff0c;然而在城市建设过程中&#xff0c;却经常发生地下电缆、燃气管道、水管被破坏或挖断的事故&#xff0c;对居民生活和社会生产造成严重影响。以下是几起地下管线外破事故&#xff1a;…

实体门店加盟全解析:如何选择加盟项目与避免风险

对于想要开实体店或创业的人来说&#xff0c;拥有一个全面的运营方案是成功的关键。作为一名开鲜奶吧5年的创业者&#xff0c;我将为大家详细分享从选址到日常管理的实体店运营要点&#xff0c;帮助创业者少走弯路。 一、选择加盟项目 1.行业前景&#xff1a;选择一个有发展前…

CrossEntropyLoss 和NLLLoss的关系

交叉熵损失在做一件什么事? 看公式: x是预测(不需要softmax归一化),y是label, N是batch维度的数量,交叉熵损失,干了三件事. 1. 对输入在类别维度求softmax 2. 多softmax后的数,求log 3. 对(样本数, 类别数)为shape的tensor计算NLLLoss. 其中,NLLloss做的就是log取负, 和o…