SpringCloud Alibaba Sentinel实现熔断与限流

news2024/12/23 10:07:48

目录

一、简介

1.官网 & 介绍

2.下载地址

3.作用

4.如何使用

⭐解决服务使用中的各种问题

5.Sentinel与Hystrix的区别

二、安装sentinel控制台

1.sentinel组件由2部分构成

2.安装步骤

①地址

②运行命令

③访问sentinel界面

三、初始化演示工程 

1.启动nacos8848

2.新建Module

①新建项目cloudalibaba-sentinel-service8401

②pom.xml

③application.yml

④主启动类

⑤业务类FlowLimitController

3.启动sentinel8080

4.启动微服务8401

5. 启动8401微服务后查看sentienl控制台

😵刷新后会发现没有什么变化

⭐结论

四、流控规则

1.基本介绍

2.流控模式

​编辑①直接(默认)------> 快速失败

②关联

③链路

3.流控效果

①直接->快速失败(默认的流控处理)

②预热

💧源码

③排队等待

五、降级规则

1.介绍

💧熔断策略

⚪Sentinel的断路器是没有半开状态的

2.RT

​编辑①添加代码

②配置

③压测

④结论

3.异常比例

①定义

②测试 

③总结 

4.异常数

①定义

​编辑②测试

六、热点key限流

1.基本介绍

⚪官网

⚪热点参数规则

2.从HystrixCommand 到@SentinelResource

3.BlockException源码

4.编写代码

5.配置

6.测试 

7.参数例外项

①配置

②测试

③前提条件

8.其它

七、系统规则(系统自适应限流)

1.定义

2.各项配置参数说明

Load 自适应(仅对 Linux/Unix-like 机器生效)

CPU usage(1.5.0+ 版本)

平均 RT

并发线程数

入口 QPS

3.配置全局QPS

八、@SentinelResource

1.按资源名称限流+后续处理

①分别启动nacos和sentinel

②新建Module

③配置流控规则

④测试

⑤其它问题

2.按照Url地址限流+后续处理

①通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息

②业务类RateLimitController

③访问一次

④Sentinel控制台配置

⑤测试

3.上面兜底方案面临的问题

4.客户自定义限流处理逻辑

①创建CustomerBlockHandler类用于自定义限流处理逻辑

②自定义限流处理类

③RateLimitController

④启动微服务后先调用一次

⑤Sentinel控制台配置

⑥测试

⑦进一步说明

5.更多注解属性说明

①所有的代码都要用try-catch-finally方式进行处理,o(╥﹏╥)o

②Sentinel主要有三个核心Api

九、服务熔断功能

1.sentinel整合ribbon+openFeign+fallback

2.Ribbon系列

①启动nacos和sentinel

②提供者9003/9004

③消费者84

3.Feign系列

①修改84模块

②pom.xml

③application.xml

④业务类

⑤主启动

4.熔断框架比较

十、规则持久化

1.步骤

2.如何使用

3.步骤


一、简介

1.官网 & 介绍

GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)

中文:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D 

2.下载地址

Releases · alibaba/Sentinel (github.com)

链接:Spring Cloud Alibaba_免费高速下载|百度网盘-分享无限制 (baidu.com)
提取码:rt3w 

3.作用

4.如何使用

Spring Cloud Alibaba Reference Documentation (spring-cloud-alibaba-group.github.io)

⭐解决服务使用中的各种问题

5.Sentinel与Hystrix的区别

具体参考:技术选型:Sentinel vs Hystrix-阿里云开发者社区 (aliyun.com)

总结:

Hystrix常用的线程池隔离会造成线程上下切换的overhead比较大;Hystrix使用的信号量隔离对某个资源调用的并发数进行控制,效果不错,但是无法对慢调用进行自动降级;Sentinel通过并发线程数的流量控制提供信号量隔离的功能;

此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。

二、安装sentinel控制台

1.sentinel组件由2部分构成

2.安装步骤

①地址

链接:Spring Cloud Alibaba_免费高速下载|百度网盘-分享无限制 (baidu.com)
提取码:rt3w 

②运行命令

java -jar "E:\down\sentinel-dashboard-1.8.1 (1).jar"(这里使用的是绝对路径)

③访问sentinel界面

Sentinel Dashboard

(账号密码均为sentinel) 

三、初始化演示工程 

1.启动nacos8848

2.新建Module

①新建项目cloudalibaba-sentinel-service8401

②pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2022</artifactId>
        <groupId>com.atxupt.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

③application.yml

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

④主启动类

package com.atxupt.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

⑤业务类FlowLimitController

package com.atxupt.springcloud.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}

3.启动sentinel8080

命令:java -jar "E:\down\sentinel-dashboard-1.8.1 (1).jar"

地址:Sentinel Dashboard

4.启动微服务8401

5. 启动8401微服务后查看sentienl控制台

😵刷新后会发现没有什么变化

原因:Sentinel采用的是懒加载(需要执行一次访问)

http://localhost:8401/testA

http://localhost:8401/testB

再次查看控制台

⭐结论

sentinel8080正在监控微服务8401         

四、流控规则

1.基本介绍

2.流控模式

①直接(默认)------> 快速失败

方式1:

方式2(效果相同):

这里采用方式1进行添加

单机阈值为1表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

测试:如果刷新速度过快,就会提示以下信息(被sentinel限流) 

思考!!!!! 

切换为线程数进行测试

疯狂点击刷新 

发现并不会有什么异常

在controller类中添加代码

@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA()
    {
        //暂停0.8秒
        try {
            TimeUnit.MILLISECONDS.sleep(800);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}

再次疯狂点击刷新(注意!!!重启服务后需要重新配置sentinel中的内容)  

②关联

Ⅰ、配置A

  • 设置效果
  • 当关联资源/testB的qps阈值超过1时,就限流/testA的Rest访问地址
  • 当关联资源到阈值后限制配置好的资源名

Ⅱ、Apifox模拟并发密集访问testB

  • 添加相关信息

模拟并发密集访问testB 

Ⅲ、 运行测试

③链路

多个请求调用了同一个微服务

3.流控效果

①直接->快速失败(默认的流控处理)

②预热

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

官网:流量控制 · alibaba/Sentinel Wiki (github.com)

  • 默认coldFactor为3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
  • 限流 冷启动:限流 冷启动 · alibaba/Sentinel Wiki (github.com) 
  • 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

  • 这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

  • 它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,换言之,我们更像一个 Token Bucket。

  • 我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;每秒这个令牌桶会自动掉落b个令牌。

  • 令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。

💧源码

com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

🥥WarmUp配置

  • 多次点击http://localhost:8401/testB :刚开始不行,后续慢慢OK
  • 应用场景(如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值)

③排队等待

匀速排队,阈值必须设置为QPS

设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

官网解释

测试 

为了打印出效果,修改FlowLimitController 代码,添加@Slf4j注解并打印信息       

(修改完成后需要重启项目,注意:可能需要在sentinel控制台重新配置!!!!!) 

@RestController
@Slf4j
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        log.info(Thread.currentThread().getName()+"\t"+"testB");
        return "------testB";
    }
}

在Apifox中进行测试

五、降级规则

1.介绍

官网介绍:熔断降级 · alibaba/Sentinel Wiki · GitHub

  • 现代微服务架构都是分布式的,由非常多的服务组成。
  • 不同服务之间相互调用,组成复杂的调用链路。
  • 以上的问题在链路调用中会产生放大的效果。
  • 复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用
  • 因此我们需要对不稳定的弱依赖服务调用进行熔断降级
  • 暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
  • 熔断降级作为保护自身的手段
  • 通常在客户端(调用端)进行配置。 

💧熔断策略

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。

  • Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
  • 当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。 

⚪Sentinel的断路器是没有半开状态的

半开的状态:系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。

具体可以参考Hystrix

2.RT

①添加代码

@GetMapping("/testD")
public String testD()
{
    //暂停几秒钟线程
    try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    log.info("testD 测试RT");
    return "------testD";
}

②配置

慢调用比例 :选择以慢调比例作为阈值,要设置允许的慢调用 RT,请求的响应时间大于该值则统计为慢调用。单位统计时长内请求数目大于设置的最小请求数目,慢调用的比例大于阈值,则接下熔断时长内请求会自动熔断

③压测

暂停测试后,再次访问,恢复正常

④结论

按照上述配置,永远一秒钟进来10个线程(大于5个了)调用testD

我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了

后续停止测试,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK 

3.异常比例

①定义

②测试 

编写代码

@GetMapping("/testD")
public String testD()
{
    log.info("testD 测试RT");
    int age = 10/0;
    return "------testD";
}

添加配置 

访问localhost:8401/testD 

按照上述配置单独访问一次 

③总结 

按照上述配置

单独访问一次,必然来一次报错一次(int age  = 10/0),调一次错一次;

  • 开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。
  • 断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。

4.异常数

①定义

异常数是按照分钟统计的

时间窗口一定要大于等于60秒。

②测试

编写代码

@GetMapping("/testE")
public String testE()
{
    log.info("testE 测试异常数");
    int age = 10/0;
    return "------testE 测试异常数";
}

直接访问会报错

达到5次报错后,进入熔断后降级

六、热点key限流

1.基本介绍

  • 热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作
  • 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
  • Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
  • 热点参数限流支持集群模式。

⚪官网

热点参数限流 · alibaba/Sentinel Wiki (github.com)

 

⚪热点参数规则

2.从HystrixCommand 到@SentinelResource

3.BlockException源码

com.alibaba.csp.sentinel.slots.block.BlockException

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.slots.block;

/**
 * Abstract exception indicating blocked by Sentinel due to flow control,
 * circuit breaking or system protection triggered.
 *
 * @author youji.zj
 */
public abstract class BlockException extends Exception {

    private static final int MAX_SEARCH_DEPTH = 10;

    public static final String BLOCK_EXCEPTION_FLAG = "SentinelBlockException";
    public static final String BLOCK_EXCEPTION_MSG_PREFIX = "SentinelBlockException: ";

    /**
     * <p>this constant RuntimeException has no stack trace, just has a message
     * {@link #BLOCK_EXCEPTION_FLAG} that marks its name.
     * </p>
     * <p>
     * Use {@link #isBlockException(Throwable)} to check whether one Exception
     * Sentinel Blocked Exception.
     * </p>
     */
    public static RuntimeException THROW_OUT_EXCEPTION = new RuntimeException(BLOCK_EXCEPTION_FLAG);

    public static StackTraceElement[] sentinelStackTrace = new StackTraceElement[] {
        new StackTraceElement(BlockException.class.getName(), "block", "BlockException", 0)
    };

    static {
        THROW_OUT_EXCEPTION.setStackTrace(sentinelStackTrace);
    }

    protected AbstractRule rule;
    private String ruleLimitApp;

    public BlockException(String ruleLimitApp) {
        super();
        this.ruleLimitApp = ruleLimitApp;
    }

    public BlockException(String ruleLimitApp, AbstractRule rule) {
        super();
        this.ruleLimitApp = ruleLimitApp;
        this.rule = rule;
    }

    public BlockException(String message, Throwable cause) {
        super(message, cause);
    }

    public BlockException(String ruleLimitApp, String message) {
        super(message);
        this.ruleLimitApp = ruleLimitApp;
    }

    public BlockException(String ruleLimitApp, String message, AbstractRule rule) {
        super(message);
        this.ruleLimitApp = ruleLimitApp;
        this.rule = rule;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }

    public String getRuleLimitApp() {
        return ruleLimitApp;
    }

    public void setRuleLimitApp(String ruleLimitApp) {
        this.ruleLimitApp = ruleLimitApp;
    }

    public RuntimeException toRuntimeException() {
        RuntimeException t = new RuntimeException(BLOCK_EXCEPTION_MSG_PREFIX + getClass().getSimpleName());
        t.setStackTrace(sentinelStackTrace);
        return t;
    }

    /**
     * Check whether the exception is sentinel blocked exception. One exception is sentinel blocked
     * exception only when:
     * <ul>
     * <li>the exception or its (sub-)cause is {@link BlockException}, or</li>
     * <li>the exception's message or any of its sub-cause's message is prefixed by {@link #BLOCK_EXCEPTION_FLAG}</li>
     * </ul>
     *
     * @param t the exception.
     * @return return true if the exception marks sentinel blocked exception.
     */
    public static boolean isBlockException(Throwable t) {
        if (null == t) {
            return false;
        }

        int counter = 0;
        Throwable cause = t;
        while (cause != null && counter++ < MAX_SEARCH_DEPTH) {
            if (cause instanceof BlockException) {
                return true;
            }
            if (cause.getMessage() != null && cause.getMessage().startsWith(BLOCK_EXCEPTION_FLAG)) {
                return true;
            }
            cause = cause.getCause();
        }

        return false;
    }

    public AbstractRule getRule() {
        return rule;
    }
}

4.编写代码

在FlowLimitController中添加代码

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "del_testHotKey")
public String testHotkey(@RequestParam(value = "p1",required = false) String p1,
                         @RequestParam(value = "p2",required = false) String p2){
    return "-------testHotKey";
}
//兜底的方法
public String del_testHotKey(String p1, String p2, BlockException exception){
    return "-------testHotKey,(((φ(◎ロ◎;)φ)))";
}

5.配置

  • 限流模式只支持QPS模式,固定写死了。(这才叫热点)
  • @SentinelResource注解的方法参数索引,0代表第一个参数,1代表第二个参数,以此类推
  • 单机阈值以及统计窗口时长表示在此窗口时间超过阈值就限流。
  • 上面的抓图就是第一个参数有值的话,1秒的QPS为1,超过就限流,限流后调用dealHandler_testHotKey支持方法

6.测试 

7.参数例外项

(类似vip特权)

①配置

配置完成后记得点击添加!!! 

②测试

localhost:8401/testHotKey?p1=5

③前提条件

热点参数的注意点,参数必须是基本类型或者String

8.其它

七、系统规则(系统自适应限流)

1.定义

系统自适应限流 · alibaba/Sentinel Wiki (github.com)

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

2.各项配置参数说明

  • Load 自适应仅对 Linux/Unix-like 机器生效

系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5

  • CPU usage(1.5.0+ 版本)

当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。

  • 平均 RT

当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

  • 并发线程数

当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

  • 入口 QPS

当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

3.配置全局QPS

八、@SentinelResource

1.按资源名称限流+后续处理

①分别启动nacos和sentinel

②新建Module

  • 修改模块cloudalibaba-sentinel-service8401中的配置
  • pom.xml

添加配置

  • application.yml
 
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'
 
  • 业务类RateLimitController
package com.atxupt.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }
}
  • 主启动类(没有变化)

③配置流控规则

项目重新启动后访问:localhost:8401/byResource

  • 配置步骤

当刷新速率过快 

  • 图形配置和代码关系

  • 表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流

④测试

  • 1秒钟点击1下,OK

  • 超过上述,疯狂点击,返回了自己定义的限流处理信息,限流发生其它的问题

⑤其它问题

  • 此时关闭问服务8401看看

  • Sentinel控制台,流控规则消失了?????

临时/持久?

2.按照Url地址限流+后续处理

①通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息

②业务类RateLimitController

package com.atxupt.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
}

③访问一次

http://localhost:8401/rateLimit/byUrl

④Sentinel控制台配置

⑤测试

疯狂点击localhost:8401/rateLimit/byUrl

结果(会返回Sentinel自带的限流处理结果)

3.上面兜底方案面临的问题

4.客户自定义限流处理逻辑

①创建CustomerBlockHandler类用于自定义限流处理逻辑

②自定义限流处理类

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atxupt.springcloud.entities.CommonResult;

public class CustomerBlockHandler {
    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler1");
    }
    public static CommonResult handleException2(BlockException exception){
        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler2");
    }
}

③RateLimitController

package com.atxupt.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atxupt.springcloud.alibaba.myhandler.CustomerBlockHandler;
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
    /**
     * 自定义通用的限流处理逻辑,
     blockHandlerClass = CustomerBlockHandler.class
     blockHandler = handleException2
     上述配置:找CustomerBlockHandler类里的handleException2方法进行兜底处理
     */
    /**
     * 自定义通用的限流处理逻辑
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
                      blockHandlerClass = CustomerBlockHandler.class, 
                      blockHandler = "handleException2")
    public CommonResult customerBlockHandler() {
        return new CommonResult(200,"按客户自定义限流处理逻辑");
    }
}

④启动微服务后先调用一次

⑤Sentinel控制台配置

⑥测试

快速刷新

⑦进一步说明

5.更多注解属性说明

①所有的代码都要用try-catch-finally方式进行处理,o(╥﹏╥)o

②Sentinel主要有三个核心Api

九、服务熔断功能

1.sentinel整合ribbon+openFeign+fallback

2.Ribbon系列

①启动nacos和sentinel

②提供者9003/9004

⚪pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2022</artifactId>
        <groupId>com.atxupt.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-provider-payment9004</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atxupt.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

⚪application.yml

  • 9003的application.yml
server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 9004的application.yml
server:
  port: 9004

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

⚪主启动类

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

⚪业务类

package com.atxupt.springcloud.alibaba.controller;

import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long, Payment> hashMap = new HashMap<>();
    static
    {
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }
}

⚪测试地址 

http://localhost:9003/paymentSQL/1

http://localhost:9004/paymentSQL/1

③消费者84

🐟 新建项目cloudalibaba-consumer-nacos-order84

🐟 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2022</artifactId>
        <groupId>com.atxupt.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-consumer-nacos-order84</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atxupt.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

🐟 application.yml

server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider

🐟 主启动类

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

🐟 业务类

  • 🐟 🐟 ApplicationContextConfig
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
  • 🐟 🐟 CircleBreakerController 

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback")
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
}

分别启动84、9003、9004 

测试地址:http://localhost:84/consumer/fallback/1 

此时的sentinel控制台

  • 没有任何配置时: 给客户返回error页面,看起来不友好

  • 只配置fallback 

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //1.@SentinelResource(value = "fallback")  什么都没有配置
    //fallback只负责业务异常
    @SentinelResource(value = "fallback",fallback = "handlerFallback")
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
    //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }

重启项目

访问localhost:84/consumer/fallback/4

  • 只配置blockHandler

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //1.@SentinelResource(value = "fallback")  什么都没有配置
    //2.只配置fallback,fallback只负责业务异常
    // @SentinelResource(value = "fallback",fallback = "handlerFallback")

    //3.只配置blockHandler,blockHandler只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback",blockHandler = "blockHandler")
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
//    //fallback
//    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
//        Payment payment = new Payment(id,"null");
//        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
//    }
    //blockHandler
      public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
          Payment payment = new Payment(id,"null");
          return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
      }
}

重新启动84项目,由于配置了blockHandler,因此需要在sentinel控制台进行配置

第一次发起请求 

疯狂点击几次后:

id换为5会有同样的效果

  • fallback和blockHandler都配置
@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //1.@SentinelResource(value = "fallback")  什么都没有配置
    //2.只配置fallback,fallback只负责业务异常
    //@SentinelResource(value = "fallback",fallback = "handlerFallback")

    //3.只配置blockHandler,blockHandler只负责sentinel控制台配置违规
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler")
    
    //4.两个都配置
    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
//    //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
    //blockHandler
      public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
          Payment payment = new Payment(id,"null");
          return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
      }
}

重启项目后添加配置 

访问速度过快

若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。 

  • 忽略的属性

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //1.@SentinelResource(value = "fallback")  什么都没有配置
    //2.只配置fallback,fallback只负责业务异常
    //@SentinelResource(value = "fallback",fallback = "handlerFallback")

    //3.只配置blockHandler,blockHandler只负责sentinel控制台配置违规
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler")

    //4.两个都配置
//    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")

    //5.本例sentinel无配置
    @SentinelResource(value = "fallback",
            fallback = "handlerFallback",
            blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
   //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
    //blockHandler
      public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
          Payment payment = new Payment(id,"null");
          return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
      }
}

 

3.Feign系列

①修改84模块

  • 84消费者调用提供者9003
  • Feign组件一般是消费侧

②pom.xml

引入依赖

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

③application.xml

添加配置

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true  

④业务类

  • Ⅰ、带@FeignClient注解的业务接口
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * 使用 fallback 方式是无法获取异常信息的,
 * 如果想要获取异常信息,可以使用 fallbackFactory参数
 */
@FeignClient(value = "nacos-payment-provider",
        fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
  • Ⅱ、fallback = PaymentFallbackService.class
import com.atxupt.springcloud.entities.CommonResult;
import com.atxupt.springcloud.entities.Payment;
import org.springframework.stereotype.Component;

@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(444,
                "服务降级返回,没有该流水信息",
                new Payment(id, "errorSerial......"));
    }
}
  • Ⅲ、Controller
@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //1.@SentinelResource(value = "fallback")  什么都没有配置
    //2.只配置fallback,fallback只负责业务异常
    //@SentinelResource(value = "fallback",fallback = "handlerFallback")

    //3.只配置blockHandler,blockHandler只负责sentinel控制台配置违规
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler")

    //4.两个都配置
//    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")

    //5.本例sentinel无配置
    @SentinelResource(value = "fallback",
            fallback = "handlerFallback",
            blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }
   //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,
                "兜底异常handlerFallback,exception内容  "+
                e.getMessage(),
                payment);
    }
    //blockHandler
      public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
          Payment payment = new Payment(id,"null");
          return new CommonResult<>(445,
                  "blockHandler-sentinel限流,无此流水: blockException  "+
                          blockException.getMessage(),
                          payment);
      }
    //OpenFeign
    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/openfeign/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        if(id == 4)
        {
            throw new RuntimeException("没有该id");
        }
        return paymentService.paymentSQL(id);
    }
}

⑤主启动

添加@EnableFeignClients启动Feign的功能

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

http://localhost:84/consumer/paymentSQL/1

测试84调用9003,此时故意关闭9003微服务提供者,看84消费侧自动降级,不会被耗死        

4.熔断框架比较

十、规则持久化

1.步骤

一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

2.如何使用

将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

3.步骤

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis 环境搭建配置全过程【IDEA】

文章目录一、MyBatis 介绍二、MyBatis 环境搭建1.MyBatis 下载2.配置 jdk 版本3.创建 Maven 工程4.IDEA 连接数据库5.项目文件构架6.引入相关依赖7.命令行创建数据库8.数据库配置文件9.核心配置文件三、入门测试程序1.创建表准备数据2.创建 POJO 实体3.创建映射文件4.修改核心配…

如何增加 KVM 虚拟机的磁盘大小

KVM 是一种集成到 Linux 内核中的虚拟化技术。您可以使用virsh、virt-manager和GNOME Boxes等工具创建虚拟机并与 KVM 交互。 磁盘空间不足是最常见的 VM 来宾问题之一。在测试新 VM 时,您可能会故意使用较小的磁盘。随着时间的推移,您会累积文件,直到虚拟磁盘几乎已满。以…

C语言笔记

fabs用来求double类型的绝对值&#xff0c;小数点后保留6位#include<math.h> double fabs(double ) labs用来求长整型long整型的绝对值&#xff0c; long cabs(long n); abs用来求整数的绝对值&#xff0c;labs求long long的绝对值#include<stdlib.h> double ret …

初识C++ (二)

初识C 二 上节课输入输出问题的一些补充一. 缺省参数1.1 半缺省参数1.2 全缺省参数二. 函数重载2.1 重载是什么意思&#xff1f;2.2 如何区分重载函数参数类型不同参数个数不同参数顺序不同附加题1附加题22.3 c支持函数重载的原理预处理编译汇编连接总结要以一种很认真的态度去…

深度优先搜索(dfs)和广度优先搜索(bfs)

目录 一、前言 二、关于dfs和bfs有意思的小故事 三、深搜题例 1、小猫爬山链接 2、基本思路 3、代码 &#xff08;1&#xff09;python代码 四、广搜题例 1、武士风度的牛链接 2、基本思路 3、代码 &#xff08;1&#xff09;C代码 &#xff08;3&#xff09;pyth…

现在的编程语言越来越多,为什么 C 和 C++ 还没有被现在的时代淘汰呢?

C/C会不会被时代淘汰&#xff1f;这个问题跳过了一步&#xff0c;关键是这个问题&#xff1a; C/C有哪些其它语言难以代替的特殊之处&#xff1f; 1、对实现细节的控制粒度 一般我们常说&#xff1a;C/C具有较高的执行效率。其实这句话不是特别准确&#xff0c;有时候它们并…

npm报错整理

npm报错整理一、代理1. 因为使用公司的镜像源导致的403 forbidden总结一、代理 1. 因为使用公司的镜像源导致的403 forbidden 在更新脚手架的时候&#xff0c;遇到了403的报错&#xff1a; 遇到问题不要怕&#xff0c;我们根据错误去解决就好。 &#xff08;1&#xff09;首…

【黄啊码】MySQL入门—13、悲观锁、乐观锁怎么用?什么是行锁、页锁和表锁?死锁了咋办?

大家好&#xff01;我是黄啊码&#xff0c;MySQL的入门篇已经讲到第12个课程了&#xff0c;今天我们继续讲讲大白篇系列——数据库锁 目录 从数据库管理的角度对锁进行划分 共享锁也叫读锁或 S 锁 排它锁也叫独占锁、写锁或 X 锁。 意向锁&#xff08;Intent Lock&#xf…

C++库——windows下使用Qt5.15.2+mingw64+msys2编译c++数学库GSL

文章目录准备配置msys2编译GSL准备 下载gsl库的源代码。大家可以到GSL的官网下载gsl的源代码。目前版本为2.7&#xff0c;下载完成后解压缩。 下载msys2。msys2是一套在windows上运行的用于构建库和程序的工具库&#xff0c;下载地址可以使用清华源的下载地址。下载完成后&…

【论文解读】伪装物体检测 Camouflaged Object Detection

文章目录伪装物体检测 Camouflaged Object DetectionSINet v1RF模块&#xff1a;PDC模块&#xff1a;SINet v2特征提取Texture Enhanced Module 纹理增强模块Neighbor Connection Decoder 邻居连接解码器Group-Reversal Attention 组反转注意力总结伪装物体检测 Camouflaged Ob…

计算机毕业设计之java+javaweb的烯烃厂压力管道管理平台

项目介绍 系统权限按管理员和用户这两类涉及用户划分。 (a) 管理员&#xff1b;管理员使用本系统涉到的功能主要有&#xff1a;主页、个人中心、通知公告管理、用户管理、管道信息管理、单位信息管理、管道统计信息管理等功能。 (b) 用户登录进入系统可以对主页、个人中心、通…

2022高频经典前端面试题(html+css+js上篇,含答案)

博主经历过多轮面试&#xff0c;因此想将自己的面试经验以及答题技巧&#xff0c;分享给即将面试找前端工作的同学。 2022高频经典前端面试题分为上中下三篇&#xff0c;分别会有html,css,js,es6,vue,ts,nodejs,以及hr面和反问面试官几个维度去进行&#xff0c;完整的还原面试场…

在 Linux 中使用 tcp 转储命令来分析网络

前言 Tcpdump是用于分析网络和查找相关网络问题的出色工具。它会在数据包经过时捕获数据包&#xff0c;并向您显示网络上正在发生的事情和传入情况。该命令的输出显示在 STDOUT 上&#xff0c;也可以存储在文件中。 感谢开发人员&#xff0c;他们将Tcpdump保留为开源项目。它…

LinkedIn最好工具-领英精灵有哪些批量加好友方法?

领英工具-领英精灵有哪些批量加好友方法 使用领英的人都会使用领英精灵&#xff0c;因为领英精灵是目前本土做得最好的领英工具&#xff0c;具有很多强大的功能。特别是拓展人脉方面&#xff0c;提供了很多批量加好友的方法。刚使用的新手可能不知道如何操作&#xff0c;下面就…

施耐德电气“创新开放日”走进中国软件研发中心 以软件与创新驱动产业“双转型”

来源 | 施耐德电气 2022年10月27日&#xff0c;施耐德电气在位于北京亦庄的中国软件研发中心举办“创新开放日”&#xff0c;充分展示其在中国深化研发的战略布局。当天&#xff0c;施耐德电气展示了该中心成立一周年以来的创新研发成果&#xff0c;并与合作伙伴共话软件发展趋…

【jsdoc-to-markdown】一步步实现js文件的文档生成

文章目录导读开发环境安装Vs code插件&#xff1a;Doxygen Documentation Generator效果优势jsdoc-to-markdown的使用了解 jsdocjsdoc-to-markdown安装创建测试文件example.jsjsdoc-to-markdown使用jsdoc-to-markdown踩坑&#xff01;&#xff01;&#xff01;参考资料导读 这个…

【C++】一文带你吃透string的模拟实现 (万字详解)

&#x1f308;欢迎来到C专栏~~ 模拟实现string (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort&#x1f393;&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句鸡汤&#x1f914;&#…

生态流量智能终端机 水电站生态流量多媒体智能终端-视频叠加、数据采集、远程传输

平升电子生态流量智能终端机 水电站生态流量多媒体智能终端是一款集人机交互、视频叠加、4G路由、数据采集、逻辑运算与远程传输功能于一体的多媒体智能终端设备。 此款产品为水电站生态流量监测项目的专用产品&#xff0c;便于监管单位及时掌握水电站的流量下泄情况&#xff…

【Django框架】——19 Django视图 01 路由配置

文章目录一、视图介绍二、路由配置1. 配置URLconf2.编辑项目中urls.py&#xff08;根路由&#xff09;3.创建应用中 urls.py (子路路由)4.路由文件urls.py5.API讲解一、视图介绍 视图就是应⽤用中views.py⽂文件中的函数 视图的第⼀个参数必须为HttpRequest对象&#xff0c;还…

计算多张图片的移位距离

( A, B )---25*30*2---( 1, 0 )( 0, 1 ) 做一个二分类的网络分类A和B&#xff0c;让A和B的训练集中都有多张图片&#xff0c;用一种平均值的办法把多张图片等效成两张图片&#xff0c;统计两张图片的移位距离&#xff0c;并比较移位距离和迭代次数的关系。 设AB训练集都只有两…