SpringCloud Alibaba学习笔记(二)Sentinel

介绍

官网地址:https://sentinelguard.io/zh-cn/

什么是Sentinel

Sentinel 是面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。
在这里插入图片描述

Sentinel 具有以下特征:

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

完备的实时监控:Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况。

广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 SpringCloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。

完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

为什么要使用Sentinel

高并发带来的问题

在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。

服务雪崩

在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。

由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应” 。

常见的容错方案

要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。

常见的容错思路有隔离、超时、限流、熔断、降级这几种,

它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。常见的隔离方式有:线程池隔离和信号量隔离.

  1. 超时

在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。

  1. 限流

限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

  1. 熔断

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

  1. 降级

降级其实就是为服务提供一个托底方案,一旦服务无法正常调用,就使用托底方案。

常见的容错组件

  • Hystrix
    Hystrix是由Netflflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。
  • Sentinel
    Sentinel 是阿里巴巴开源的一款断路器实现,本身在阿里内部已经被大规模采用,非常稳定。
    在这里插入图片描述

Sentinel入门

快速开始

Sentinel 的使用可以分为两个部分:

  • 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。
  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

微服务集成Sentinel

1.导入依赖

        <!--sentinel持久化配置-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--sentinel-->
       <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2.编写配置

spring:
  application:
    name: web-consumer-9002
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # 如果使用nacos集群只需要配置nginx地址 IP+端口号
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:9333 # 此次得是localhost 不能是 127.0.0.1

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

3.编写一个测试controller

@RestController
public class FlowLimitController {
    
    

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

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

控制台下载

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

控制台使用原理

Sentinel的控制台其实就是一个SpringBoot编写的程序。我们需要将我们的微服务程序注册到控制台上,即在微服务中指定控制台的地址, 并且还要开启一个跟控制台传递数据的端口, 控制台也可以通过此端口调用微服务中的监控程序获取微服务的各种信息。

参考官网启动控制台

在这里插入图片描述

# 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目) 
java -Dserver.port=9333 -Dcsp.sentinel.dashboard.server=localhost:9333 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar

访问控制台

浏览器输入:http://localhost:9333/
在这里插入图片描述
( 默认用户名密码是 sentinel/sentinel )
在这里插入图片描述

(如果没有出现数据,则需要调用一下controller接口,因为sentinel默认懒加载)

流控规则

基本介绍

在这里插入图片描述

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

流控模式

QPS直接-快速失败

添加流控规则,资源名就是默认Rest请求路径
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.直接调用了默认的报错信息 Blocked by Sentinel (flow limiting)
2.是否应该有类似fallback的兜底方法

线程数直接-快速失败

勾选线程数,当前只允许一个线程进来,其他线程直接失败
在这里插入图片描述

测试运行
在这里插入图片描述

关联

当关联的资源达到阈值时,就限流自己

这是什么意思呢?

@RestController
public class FlowLimitController {
    
    
// 同一个controller下的两个接口  A B
//当 A 关联的 B资源达到阈值时,就限流A 自己
//意思是 B惹事 A挂了 
  @GetMapping("/testA")
  public String testA() throws InterruptedException {
    
    
    Thread.sleep(1000);
    return "-----------TestA";
  }

  @GetMapping("/testB")
  public String testB() throws InterruptedException {
    
    
    Thread.sleep(1000);
    return "-----------TestB";
  }
}

这样有什么用呢?
比如说我们支付接口达到阈值以后,就限流下订单的接口,防止连坐效应

设置关联:
在这里插入图片描述
使用Postman并发测试访问
1.将接口加入集合中
在这里插入图片描述
2.点击集合,打开run
在这里插入图片描述
3.设置调用次数20次,300毫秒调用一次
在这里插入图片描述

4.点击运行

在这里插入图片描述
5.此时访问接口A,发现已经被限流了
在这里插入图片描述

链路

指定资源从入口资源进来的流量,如果达到阈值,就进行限流

此处就不再进行过多演示

流控效果

快速失败

默认的限流处理,直接失败,抛出异常:Blocked by Sentinel (flow limiting)

Warm Up(预热)

说明:根据codeFactor(冷加载因子,默认3)的值,从阈值codeFactor,经过预热时长,才达到设置的QPS阈值

官方解释:

当系统长期处于低水位的情况下,流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。比如刚启动的服务,数据库连接池可能还未初始化,缓存也处于空的状态,这时候激增的流量非常容易导致服务崩溃。这时我们就可以利用 Sentinel 的 Warm-Up 流控模式,控制通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,而不是在一瞬间全部放行。这样可以给冷系统一个预热的时间,避免冷系统被压垮。
在这里插入图片描述

什么是codeFactor(冷加载因子,默认3)

比如说:我们当前阈值10 预热时长5
当我们系统一开始启动的时候 真实阈值是 10/3=3 而过了五秒钟以后 阈值会慢慢增加到10
在这里插入图片描述
官网源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

 public WarmUpController(double count, int warmUpPeriodInSec) {
    
    
                       //冷加载因子 3
        construct(count, warmUpPeriodInSec, 3);
    }

排队等待

匀速排队:让请求均匀的速度通过,阈值类型必须设置成QPS,否则无效
含义:/testA每秒1次请求,超过的话就排队等待,等待超时时间20000毫秒
在这里插入图片描述

降级规则

官网概述

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
在这里插入图片描述
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的 弱依赖服务调用 进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

注意:本文档针对 Sentinel 1.8.0 及以上版本。1.8.0 版本对熔断降级特性进行了全新的改进升级,请使用最新版本以更好地利用熔断降级的能力。

熔断策略

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熔断降级会在调用链路中某个资源出现不稳定状态时(列如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他资源而导致级联错误

当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)

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

什么是半开状态?

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

降级模式

慢调用比例

准备测试方法controller:

  @GetMapping("/testD")
  public String testD(){
    
    
    try {
    
    
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
    
    
      e.printStackTrace();
    }
    return "---------TestD";
  }

在这里插入图片描述
设置最大响应时间:200毫秒
如果调用接口时间超过最大响应时间则记为慢调用
当慢调用的比例超过:1 = 100%
则进行熔断

依旧还是postman测试
在这里插入图片描述
熔断会抛出异常:Blocked by Sentinel (flow limiting)

异常比例

准备测试方法:

  @GetMapping("/testD")
  public String testD(){
    
    
    int age = 10/0; //此处百分之百抛异常
    return "---------TestD";
  }

当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
在这里插入图片描述
此时如果每秒请求数>=5 异常比例大于80% 则会开启熔断器
在这里插入图片描述
如果请求数<5 异常比例大于80%的话 则会报错提示
在这里插入图片描述
结论:

1.单独访问一次,必然来一次报错一次(ing age = 10/0),调用一次错一次
2.在postman开启集合并发请求的时候,多次调用达到我们的配置条件了,断路器开启(保险丝熔断),微服务不可用,直接降级

异常数

当单位统计时长内的异常数目超过阈值之后会自动进行熔断。

异常数是按分钟统计的

依旧还是这个测试方法:

  @GetMapping("/testD")
  public String testD(){
    
    
    TimeUnit.SECONDS.sleep(1);
    int age = 10/0; //此处百分之百抛异常
    return "---------TestD";
  }

在这里插入图片描述
当异常数>5 最小请求数>=3时 触发降级
在这里插入图片描述

热点Key限流

官网概述

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

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

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

官网源码:com.alibaba.csp.sentinel.slots.block.BlockException

兜底方法

分为系统默认和客户自定义,两种

在之前限流出问题后,都是用Sentinel系统默认提示:Blocked by Sentinel (flow limiting)

我们能不能自定义?类似某个方法出问题了,就找到对应的兜底降级方法?

在Sentinel中@SentinelResource 就是来完成这件事的

限流测试

准备controller测试方法:

  @GetMapping("/testHotKey")
  @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") // value 名称唯一 就行
  public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                           @RequestParam(value = "p2", required = false) String p2){
    
    
    return "----------testHotKey";
  }
  
  // 兜底方法 必须加上BlockException blockException
  public String deal_testHotKey(String p1, String p2, BlockException blockException){
    
    
    return "testHotKey兜底方法";
  }

配置热点限流
在这里插入图片描述
注意:资源名称和要限流的参数索引

配置解析:

1.@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") 配置了资源名称,在控制台会对其监控,如果出现异常则走我们定义好的deal_testHotKey兜底方法

2.监控第0个参数也就是p1参数,当请求QPS超过阈值1,则达到限流条件
在这里插入图片描述

参数例外项

上述案例演示了第一个参数p1,当QPS超过1秒一次点击后马上被限流

特例情况:
我们期望p1参数当它是某一个特殊值时,它的限流值和平时不太一样,
换句话说当p1的参数等于5,它的阈值可以达到200
在这里插入图片描述
配置解析:

1.当传递给接口的参数p1=5时,阈值从1变到200
2.参数例外项只配置支持八种基本类型和String类型

扩展知识:

  1. @SentinelResource处理的是控制台违规情况,有blockHandler兜底方法,如果方法本身抛出异常,它不进行处理
  @GetMapping("/testHotKey")
  @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") // value 名称唯一 就行
  public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                           @RequestParam(value = "p2", required = false) String p2){
    
    
    int age = 10/0; //运行时异常 不被@SentinelResource处理
    return "----------testHotKey";
  }
  1. int age = 10/0;是Java运行时异常RuntimeException,不会被处理
  2. @SentinelResource主管配置出错,运行出错该走哪就走哪

系统规则

官网概述

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

(在我们之前的例子中,所进行的配置都是针对某一个具体的接口进行设计,是细粒度的控制)
在这里插入图片描述

各参数配置说明

在这里插入图片描述
系统规则支持以下的阈值类型

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。

  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。

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

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

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

总结

1.系统规则设置的是全局
2.比如说设置QPS=1,那么这个系统的所有接口都只能一秒钟点击一次,否则会降级
3.系统规则不像之前例子中进行细粒度的划分,A接口阈值10,B接口阈值200

@SentinelResource详解

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

准备测试方法:

    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "deal_byResource")
    public String byResource(){
    
    
        return "按资源名称进行限流测试-OK";
    }

    public String deal_byResource(BlockException blockException){
    
    
        return "按资源名称进行限流测试---兜底方法";
    }

在控制台中,选择资源名称进行配置限流规则
在这里插入图片描述
在这里插入图片描述

测试发现:超过单机阈值以后会执行降级,走我们定义的兜底方法

额外问题:
当我们关闭服务以后,会发现配置的限流规则消失了!

按Url地址限流+后续处理

通过URL限流,会返回Sentinel自带默认提示

准备测试方法:

  // 可以看到此处在@SentinelResource并没有配置降级方法
    @GetMapping("/byResource1")
    @SentinelResource(value = "byResource")
    public String byResource1(){
    
    
        return "按资源名称进行限流测试-OK";
    }

配置降级规则:
在这里插入图片描述
测试:
在这里插入图片描述
会返回Sentinel自带的限流处理

兜底方案面临的问题

1.兜底方案跟业务代码耦合在一块,不直观
2.每个方法都得有一个兜底方法,导致代码膨胀
3.全局统一的处理方法没有体现
4.系统默认的,没有体现出我们自己的业务要求

客户自定义限流处理逻辑

为解决兜底方案面临的问题,我们现在需要自定义限流处理逻辑!

步骤:

  • 创建CustomerBlockHandler类用于自定义限流处理逻辑。
  • 自定义限流处理类
  • 编写RateLimitController
  • 启动微服务后先调用一次
  • Sentinel控制台配置
  • 测试与进一步说明

编写CustomerBlockHandler类

创建CustomerBlockHandler类

public class CustomerBlockHandler {
    
    

    // 必须用static进行修饰 controller方法返回什么 这里就返回什么
    public static String handlerException(BlockException blockException){
    
    
        return "自定义限流处理逻辑-降级方法一号";
    }

    public static String handlerException2(BlockException blockException){
    
    
        return "自定义限流处理逻辑-降级方法二号";
    }
}

编写RateLimitController

    /**
     * blockHandlerClass 用那个类进行降级方法处理
     * blockHandler 用class类中的哪个降级方法
     * * @return
     */
    @GetMapping("/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler", 
    blockHandlerClass = {
    
    CustomerBlockHandler.class}, blockHandler = "handlerException")
    public String customerBlockHandler(){
    
    
        return "自定义限流处理逻辑测试-OK";
    }

Sentinel控制台配置

在这里插入图片描述

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

服务熔断功能

1.Sentinel整合ribbon+openFeign+fallback
2.Ribbon系列
3.Fegin系列
4.熔断框架比较

准备提供者测试方法:

@RestController
public class TestController {
    
    
    
    private Map<String, String> map = new HashMap<>();
    
    @PostConstruct
    public void setValue(){
    
    
        map.put("1", "王根基");
        map.put("2", "郑在搞");
        map.put("3", "疾风剑豪");
    }
    
    @GetMapping("/test/{id}")
    public String findById(@PathVariable("id") String id){
    
    
        return map.get(id);
    }
}

准备两个服务提供者8021/8022:

将原来的服务复制一份改一下端口即可
在这里插入图片描述

准备服务消费者:

1.创建项目导入依赖
2.编写主启动类
3.编写yaml
4.业务类

创建项目导入依赖:

   <dependencies>
        <!--sentinel持久化配置-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

编写主启动类

@SpringBootApplication
@EnableDiscoveryClient
public class WebApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(WebApplication.class, args);
    }
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }
}

编写yaml

server:
  port: 84
spring:
  application:
    name: web-consumer-84
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # 如果使用nacos集群只需要配置nginx地址 IP+端口号
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:9333      
management:
  endpoints:
    web:
      exposure:
        include: '*'
feign:
  sentinel:
    enabled: true #如果使用feign做远程调用一定要开启sentineld对feign的支持        

编写服务消费者业务类:

@RestController
public class TestController {
    
    

    @Autowired
    private RestTemplate restTemplate;
    //注册到nacos的服务提供者这 服务名
    private static String URL = "http://nacos-provider";

    @GetMapping("/{id}")
    @SentinelResource(value = "fallback")
    public String findById(@PathVariable("id") String id){
    
    
        if (id.equals("4")){
    
    
            throw new IllegalArgumentException("非法参数异常");
        }else if (restTemplate.getForObject(URL+"/test/"+id, String.class) == null){
    
    
            throw new NullPointerException("空指针异常");
        }
        return restTemplate.getForObject(URL+"/test/"+id, String.class);
    }
}

测试运行:

1.成功注册进nacos
在这里插入图片描述
2.成功注册到sentinel中显示
在这里插入图片描述

fallback

上面的代码编写完成以后,我们测试运行发现

当后台代码抛出异常时,返回的时一个错误页面,这十分不友好
在这里插入图片描述
还记得我我们之前说的 @SentinelResourc的blockHandler兜底方法处理的是控制台违规情况,如果方法本身抛出异常,它不进行处理

那么如何处理异常呢?

这个时候我们就要使用到了fallback,它是处理异常的

@RestController
public class TestController {
    
    

    @Autowired
    private RestTemplate restTemplate;
    //注册到nacos的服务提供者这 服务名
    private static String URL = "http://nacos-provider";

    @GetMapping("/{id}")
    @SentinelResource(value = "fallback", fallback = "handlerFallback")
    public String findById(@PathVariable("id") String id){
    
    
        if (id.equals("4")){
    
    
            throw new IllegalArgumentException("非法参数异常");
        }else if (restTemplate.getForObject(URL+"/test/"+id, String.class) == null){
    
    
            throw new NullPointerException("空指针异常");
        }
        return restTemplate.getForObject(URL+"/test/"+id, String.class);
    }
    // 异常fallback 兜底方法
    public String handlerFallback(@PathVariable("id") String id, Throwable e){
    
    
        return e.getMessage()+"fallback异常兜底方法!";
    }
}

此时再次处理出现异常时,会走我们定义的方法

异常忽略

在这里插入图片描述

规则持久化

我们之前在控制台配置的规则都会随着服务的重启而消失,那么怎么配置持久化呢?

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

1.导入持久化依赖

    <!--sentinel持久化配置-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

2.添加数据源配置

server:
  port: 84
spring:
  application:
    name: web-consumer-84
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # 如果使用nacos集群只需要配置nginx地址 IP+端口号
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:9333
      datasource: # 配置数据源配置
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: web-consumer-84 # nacos的dataId
            groudId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
management:
  endpoints:
    web:
      exposure:
        include: '*'
feign:
  sentinel:
    enabled: true #如果使用feign做远程调用一定要开启sentineld对feign的支持

3.添加Nacos业务规则配置
在这里插入图片描述

[
    {
    
    
        "resource": "/{id}",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

配置解析:

在这里插入图片描述

测试重启服务:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46684099/article/details/119824246