SpringCloud Alibaba—Sentinel熔断与限流

一.概念

1.Sentinel是什么?

  • Sentinel: 分布式系统的流量防卫兵
    在这里插入图片描述

2.Sentinel特征?

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
    完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
    完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
    完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

3.Sentinel作用?

在这里插入图片描述


二.安装并运行Sentinel控制台

1.下载地址

https://github.com/alibaba/Sentinel/releases

2.运行命令

java -jar sentinel-dashboard-1.7.0.jar
在这里插入图片描述

3.访问

运行成功访问localhost:8080
用户名,密码为:sentinel
在这里插入图片描述

在这里插入图片描述


三.使用sentinel的基本配置

1.导入依赖

 <dependencies>

        <dependency>
            <groupId>com.sise</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--sentinel-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <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>

        <!--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>

        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <!--lombok-->
        <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>

2.配置文件

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

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

3.启动类

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

4.controller业务类

@RestController
public class sentinelController {
    @GetMapping("/testA")
    public String testA(){
        return "this is TestA";
    }

    @GetMapping("/testB")
    public String testB(){
        return "this is TestB";
    }

}

5.测试

先启动nacos和sentinel
nacos已经注册上
在这里插入图片描述
打开sentinel面板,成功注册到sentinel

(注意:sentinel默认采用的是懒加载,如果该服务没有访问过,在sentinel不会显示出来,要先访问该服务的testA和testB)
在这里插入图片描述
访问几次testA,Sentinel流量监控到了

注意:但某个请求一段时间没被访问后sentinal的监控面板会清除,当有请求进来时会继续显示
在这里插入图片描述
sentinel8080正在监控微服务8401


四.流控规则

1.基本介绍

在这里插入图片描述

  • 资源名:唯一名称,默认请求路径
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
  • 阈值类型/单机阈值
  1. QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
  2. 线程数:当调用该api的线程数达到阈值的时候,进行限流
  • 是否集群:(不)需要集群
  • 流控模式
  1. 直接:api达到限流条件时,直接限流
  2. 关联:当关联的资源达到阈值时,就限流自己
  3. 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)
  • 流控效果
  1. 快速失败:直接失败,抛异常
  2. Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。
  3. 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS。否则无效。

2.直接快速失败

在这里插入图片描述

  • 测试:当每秒请求阈值大于1时报错
    在这里插入图片描述
  • 阈值类型为线程数
    在这里插入图片描述
  • 为了演示效果给TestA延迟处理时间
@GetMapping("/testA")
public String testA(){
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "this is TestA";
}
  • 打开一个窗口访问testA,立即再打开一个浏览器访问TestA表示两个线程去访问TestA
    在这里插入图片描述

3.关联快速失败

  • 当关联的资源达到阈值时,就限流自己
    当与A关联的资源B达到阀值后,就限流A自己

  • 设置关联资源/testB:testb达到阀值后,就限流testa自己
    在这里插入图片描述

  • 使用postman模拟访问/testB

20个进程,每0.3秒访问一次
在这里插入图片描述

  • 运行,并执行testA,查看是否会关联到,成功,当postman停止之后恢复正常
    在这里插入图片描述

4.流控效果——Warm Up

  • 公式
    预热时长的时间内允许的QPS阈值:阈值除以coldFactor(默认值为3),
    超过预热时长后允许的QPS阈值:阈值

  • 解释
    Warm Up方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过“冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
    在这里插入图片描述

  • Warmup配置
    默认coldFactor3,即请求QPS从threshold / 3开始,经预热时长逐渐升至设定的QPS阈值。
    秒杀系统在开启的瞬间,会有很多流量进来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
    在这里插入图片描述

  • 测试
    结果是前5s一直访问会访问不了,5s后可以正常访问
    在这里插入图片描述

5.流控效果——排队等待

  • 解析

匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。
设置含义: /testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

这种方式:主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景, 在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

  • 配置
    testB阈值最高为1,当QPS大于1时要排队等待,超时时间为20秒
    在这里插入图片描述
  • 使用postman测试
    在这里插入图片描述
  • 结果
    在这里插入图片描述
    在这里插入图片描述


五.降级规则

1.基本介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.RT

在这里插入图片描述
在这里插入图片描述

  • 编辑降级规则
    在这里插入图片描述
  • 使用jmeter工具进行测试
    在这里插入图片描述
  • 测试结果
    在这里插入图片描述
    Jmeter停止之后,正常访问
    在这里插入图片描述
  • 结论
    在这里插入图片描述

3.异常比例

在这里插入图片描述

在这里插入图片描述

  • 编辑降级规则

如果返回比例20% 以上都是异常,那么3秒内就触发降级
在这里插入图片描述

  • 测试
    由于异常比例的规则是,但每秒的请求>=5和异常比例>一定的阈值就才会触发,所以使用jmete工具测试,使用jmeter发送每秒10个请求,10个请求的异常比例是百分之百,所以满足条件触发降级
    在这里插入图片描述
  • 结论
    在这里插入图片描述

4.异常数

在这里插入图片描述
在这里插入图片描述
异常数是按照分钟统计的

  • 新增降级规则:61秒内,当异常数大于5开启降级

在这里插入图片描述

  • 测试
    在这里插入图片描述
    前5次
    在这里插入图片描述
    后五次
    在这里插入图片描述


六.热点key限流

1.使用名称添加限规则

  • 新增RateLimitController
@RestController
public class RateLimitController {

//通过资源名称限流,限流是使用自定义的处理器(handleException)
    @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  服务不可用");
    }
}
  • 使用名称添加限规则

使用SentinelResource的value名添加限流规则,限流是使用自定义得处理器blockHandler,不使用Sentinel默认的提示
在这里插入图片描述

  • 测试

限流之后,使用的是自定义的处理信息,如果使用url的话,就会又变成Sentinel默认的提示信息(但是服务重启后,规则就消失了,所以这个是一个临时规则
在这里插入图片描述

  • 重启后
    在这里插入图片描述

2.使用url添加限规则

  • 新增业务类
@GetMapping("/rateLimit/byUrl" )
@SentinelResource(value = "byUr1")
public CommonResult byUrl(){
    return new CommonResult(  200, "按ur1限流测试oK",new Payment( 2020L,  "seria1002"));
}
  • 使用url添加限规则

使用url /rateLimit/byUrl 添加限规则后,只会使用Sentinel默认的提示信息
在这里插入图片描述

  • 测试
    在这里插入图片描述

3.全局处理方法

  • 上面出现的问题
    在这里插入图片描述
  • 编写全局处理类 CustomerBlockHandler
public class CustomerBlockHandler {

    public static CommonResult handlerException(BlockException exception){
        return new CommonResult(  444, "按客户自定义,global handlerException-------1 ");
    }
    public static CommonResult handlerException2(BlockException exception){
        return new CommonResult(  444, "按客户自定义,global handlerException-------2 ");
    }
}
  • controller新增方法
//通过名称customerBlockHandler限流之后
//使用的是自定义的处理信息CustomerBlockHandler类中的handlerException2方法
@GetMapping("/rateLimit/customerBlockHandler" )
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,blockHandler="handlerException2")
    public CommonResult customerBlockHandler(){
        return new CommonResult(  200, "按客户自定义",new Payment( 2020L,  "seria1003"));
    }

在这里插入图片描述

  • 使用资源名customerBlockHandler,添加限流规则
    在这里插入图片描述
  • 测试
    在这里插入图片描述

4.热点参数限流

  • 添加controller方法
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }

    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "------deal_testHotKey,o(╥﹏╥)o";
    }
  • 编辑热点规则
    在这里插入图片描述

  • 重启测试
    正常
    在这里插入图片描述

    含有p1的参数且超过阈值
    在这里插入图片描述
    只要不含有p1的参数,不管是否超过阈值,都为正常
    在这里插入图片描述

  • 参数例外项
    我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样,假如当p1的值等于6时,它的阈值可以达到100

  • 编辑热点规则
    在这里插入图片描述

  • 测试
    当p1为6时,他的阈值为100,不限流
    在这里插入图片描述

  • 异常
    在这里插入图片描述


七.服务熔断-Ribbon系列

1.启动nacos和sentinel

2.新建服务提供者9003/9004

  • 导入依赖
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.sise</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</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>
        <!--lombok-->
        <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>
  • 配置文件
server:
  port: 9003

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);
    }
}
  • 业务类controller
@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;
    }

}

3.创建消费者84

  • 导入依赖
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--nacos discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.sise</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--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>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <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>
  • 配置文件
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

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
  • 启动类
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
  • 负载均衡配置类
@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
  • service
@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",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}")
    //@SentinelResource(value = "fallback") //没有配置
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责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/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        return paymentService.paymentSQL(id);
    }
}

4.fallback运行异常

  • 84一开始的业务类是这样的
    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback") //没有配置,程序出现异常会出现error界面
    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;
    }
  • 没配置降级或熔断之前,访问4以前的是正常,4之后的会出现错误页面,抛异常非法参数
    在这里插入图片描述
    在这里插入图片描述
  • 配置fallback后,新增一个handlerFallback处理方法,fallback负责业务异常(运行的异常),不负责控制台违规(限流或者熔断不负责)
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置,程序出现异常会出现error界面
@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
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;
}

//兜底方法
public CommonResult<Payment> handlerFallback(Long id, Throwable e) {
    Payment payment = new Payment(id, null);
    return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
}
  • 测试
    在这里插入图片描述

5.blockHandler配置违规

如果只配置blockHandler,测试java异常时会不会处理?

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
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;
}

public CommonResult<Payment> blockHandler(Long id, BlockException blockException) {
    Payment payment = new Payment(id,"null");
    return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
}
  • 新增降级规则
    在这里插入图片描述
    在这里插入图片描述

  • 测试
    配置blockHandler后,新增一个blockHandler处理方法,blockHandler负责配置的控制台违规(限流或者熔断不负责),不负责业务异常(运行的异常)

点击请求一次,达不到降级规则,还是出现异常页面
在这里插入图片描述
一直点击请求,当达到降级规则时,才会出现定制页面
在这里插入图片描述

6.配置fallback和blockHandler

  • 修改注解
@SentinelResource(value = "fallback",
blockHandler = "blockHandler",fallback = "handlerFallback")
  • 添加流控规则,每秒请求只能有1个,多了限流
    在这里插入图片描述
    测试

点击一秒一次,进入fallback
在这里插入图片描述
达到流控规则,进入blockHandler
在这里插入图片描述

  • 结论
    在这里插入图片描述

7.exceptionsToIngnore属性

在这里插入图片描述

  • 测试

参数为5时,进入fallback方法
在这里插入图片描述

参数为4时
在这里插入图片描述


八.服务熔断-Feign系列

1.修改84模块,添加依赖

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

2.添加配置文件

#对Feign的支持
feign:
  sentinel:
    enabled: true

3.添加feign接口

@FeignClient(value = "nacos-payment-provider")
public interface paymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

4.编写实现类

用于处理熔断后的处理方法,注意加@Component

@Component
public class paymentServiceImpl implements paymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

5.指定对应的类,来处理降级

在这里插入图片描述

6.添加controller

// OpenFeign
@Resource
private PaymentService paymentService;

@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
    return paymentService.paymentSQL(id);
}

7.@EnableFeignClients

在主启动类上添加开启feign注解@EnableFeignClients
在这里插入图片描述

8.测试

测试84调用9003,9004,此时故意关闭9003微服务提供者,看84消费侧自动降级,不会被耗死
在这里插入图片描述


九.Sentinel持久化规则

一般我们在sentinel中制定一个规则给服务后,当该服务重启后规则就没了,所以需要配合nacos进行持久化

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

以cloud-alibaba-sentinel-service8401为测试

1.添加依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2.添加配置

spring:
   cloud:
    sentinel:
    datasource:
     ds1:
      nacos:
        server-addr:localhost:8848
        dataid:${spring.application.name}
        groupid:DEFAULT_GROUP
        data-type:json
            rule-type:flow

支持多种持久化,这里采用nacos持久化
在这里插入图片描述

3.在nacos里新建配置

在这里插入图片描述
内容解释

/rateLimit/byUrl对这个请求进行限流,可以配置多个请求

[
{
“resource”: “/rateLimit/byUrl”,
“limitApp”: “default”,
“grade”: 1,
“count”: 1,
“strategy”: 0,
“controlBehavior”: 0,
“clusterMode”: false
}
]
在这里插入图片描述
在这里插入图片描述

4.运行8401就直接有流控规则在

在这里插入图片描述

5.测试

请求达到限流规则,进行限流处理
在这里插入图片描述

处理规则服务启动先去nacos拿限流配置文件,匹配规则前面nacos笔记有,然后注册sentinel时限流配置一起注册配置上去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值