在上一篇讲了sentinel的介绍,安装Sentinel控制台、初始化演示工以及程流控规则
    
    
    
     接下来学习熔断规则,热点key限流,系统规则,@SentinelResource注解,服务熔断功能以及规则持久化。
    
   
    
    
    熔断规则
   
    
    
    
     
      官方介绍
     
    
   
- 
     基本介绍
 
  
 
 
 熔断策略
 
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
 
 )不生效。
- 
     RT(平均响应时间,秒级)
 
 平均响应时间 超出阈值 且 在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
 
 窗口期过后关闭断路器
 
 RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
    
     熔断降级规则(DegradeRule)包含下面几个重要的属性:
    
   
| 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 引入) | 
    Sentinel的断路器是
    
     没有半开状态
    
    的
    
    半开的状态系统自动去检测是否请求有异常,
    
    没有异常就关闭断路器恢复使用,
    
    有异常则继续打开断路器不可用。具体可以参考Hystrix
   
    
    
    (1)慢调用比例
   
选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
- 添加一个测试接口,调用接口时休眠2秒,使得此接口的响应时间为1秒以上
@GetMapping("/testD")
public String testD()
{
    //暂停几秒钟线程
    try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    log.info("testD 测试调用比例");
    return "------testD";
}
- 
     控制台添加测试接口熔断规则
 
   
- 
     
 最大 RT
 
 :慢调用临界 RT,超出该值计为慢调用。单位毫秒
- 
     
 比例阈值
 
 :RT模式下慢速请求比率的阈值。默认1.0d
- 
     
 熔断时长
 
 :断路器打开时的恢复超时(以秒为单位)。超时后,断路器将转换为半开状态以尝试一些请求。单位秒,图中表示触发熔断后,接下来的10秒内请求会自动被熔断,经过10S后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
- 
     
 最小请求数
 
 :可以触发熔断中断的最小请求数(在有效的统计时间范围内)。默认值为5
- 
     
 StatIntervalMs
 
 : 统计时长(单位为 ms),如 601000 代表分钟级(1.8.0 引入),默认1000,在控制台没有选项,需代码实现。
    使用
    
     jemeter
    
    测试
   
    
     
   
使用压测工具访问测试接口,查看限流效果图,具体限流过程大概为:
(1)请求进入后台,sentinel会根据设置的统计时长(默认1S)统计时间段内请求的总数
(2)首先判断统计的请求总数是否小于用户的设置的最小请求数(默认5),小于则不熔断,反之则进入下一步
(3)然后根据用户设置的最大 RT,判断统计中的请求是否为慢调用,大于设置值为是慢调用请求
(4)再次计算慢调用请求/总统计请求比例,是否超过设置的比例阈值。
(5)当统计时间内的请求数及慢调用比例阈值都超过设置的阈值后,接下来的熔断时长内请求会自动被熔断
(6)熔断时长结束后,熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
————————————————
版权声明:本文为CSDN博主「云烟成雨csdn」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43437874/article/details/111475762
    结论:
    
    
     永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,
     
     如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
     
     后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK
    
   
    
    
    (2)异常比例
   
    
     异常比例 (ERROR_RATIO)
    
    :当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% – 100%。
   
- 在controller添加以下方法
@GetMapping("/testE")
public String testE()
{
    log.info("testE 测试异常比例");
    int age = 10/0;
    return "------testE";
}
- 
     控制台添加测试接口熔断规则
 
  
 
 访问
 
 http://127.0.0.1:8401/testE
 
 
  
 
 直接报错了,直接再刷新。
 
  
 
 因为多次调用
 
 达到我们的配置熔断降级条件了,断路器开启(保险丝跳闸)
 
 ,微服务不可用了,不再报错error而是服务降级了。
    
    
    (3)异常数
   
    异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
    
    
     测试
    
    
    还是刚刚那个
    
     testE
    
    路径
   
- 
     控制台修改测试接口熔断规则
 
   
    访问
    
     http://127.0.0.1:8401/testE
    
    
    
    
    5s内,先访问5次,当访问了第五次了,在访问一次,也就是第六次。
    
    
    
    因为我们配置的统计时长是
    
     5s
    
    ,当5s内异常的次数达到了
    
     5次
    
    ,第
    
     6次
    
    就进行熔断降级,降级持续
    
     2s
    
    钟。
   
    
    
    热点key限流
   
    
     何为热点?
    
    
    
     热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作
    
   
    
    
    
     官方说明
    
   
- 在controller添加以下方法
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1, 
                         @RequestParam(value = "p2",required = false) String p2){
    return "------testHotKey";
}
public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
{
    return "-----dealHandler_testHotKey";
}
    
     sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    
   
- 
     配置说明
 
  
 
 正常访问
 
 http://127.0.0.1:8401/testHotKey
 
 
  
 
 访问
 
 http://127.0.0.1:8401/testHotKey?p1=1
 
 ,并不断刷新
 
  
 
 访问
 
 http://127.0.0.1:8401/testHotKey?p2=1
 
 ,并不断刷新
 
  
 
 访问
 
 http://127.0.0.1:8401/testHotKey?p2=1&p1=1
 
 ,并不断刷新
 
  
 
 
 结论,只要带有
 
 p1
 
 这个参数并且QPS超过每秒1次都要被降级处理。
 
@SentinelResource(value = "testHotKey")//异常打到了前台用户界面看到,不友好
//方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")//用了我们自己定义的
    
     上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流,但是我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样,例如:假如当p1的值等于5时,它的阈值可以达到200
    
   
- 
     修改配置
 
  
 
 配置说明:当p1等于5的时候,阈值变为200,当p1不等于5的时候,阈值就是平常的1。
    
    
    
     注意:热点参数的注意点,参数必须是基本类型或者String
    
   
    
     其他:
    
    
    
     @SentinelResource
    
    
    
     处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;
    
   
    
     RuntimeException
    
    
    
     int age = 10/0,这个是java运行时报出的运行时异常RunTimeException,@SentinelResource不管
    
   
    
     总结
    
    
    
     @SentinelResource主管配置出错,运行出错该走异常走异常
    
   
    
    
    
     系统规则
    
   
    系统保护规则是从应用级别的
    
     入口流量
    
    进行控制,从单台机器的
    
     load
    
    、
    
     CPU 使用率
    
    、
    
     平均 RT
    
    、
    
     入口 QPS
    
    和
    
     并发线程
    
    数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
   
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
    
     系统规则支持以下的模式:
    
   
- 
     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 达到阈值即触发系统保护。
 
   
    
    
    
     官方文档
    
   
    
    
    @SentinelResource的使用
   
    
    
    1.按资源名称限流以及后续处理
   
- 
     添加新的
 
 RateLimitController
 
@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 服务不可用");
    }
}
- 
     启动nacos,启动sentinel,去sentinel控制台添加
 
 流控规则
 
 
  
 
 配置说明:
 
 
 表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流
 
 
  
 
 
 1秒钟点击1下,没法发生降级。
 
 
  
 
 
 超过上述,疯狂点击,返回了自己定义的限流处理信息,限流发生
 
 
   
    
    
    2.按照Url地址限流以及后续处理
   
    在刚刚新建的类
    
     RateLimitController
    
    添加以下方法
   
@GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
    Sentinel控制台配置,新增以下配置
    
     
   
    访问
    
     http://localhost:8401/rateLimit/byUrl
    
    
    很慢的访问时
    
    
    
    疯狂点击
    
     http://localhost:8401/rateLimit/byUrl
    
    
    
    
    成功的进行了限流
   
    
    
    3.客户自定义限流处理逻辑
   
上面兜底代码存在的问题:
- 系统默认的,没有体现我们自己的业务要求。
- 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
- 每个业务方法都添加一个兜底的,那代码膨胀加剧。
- 全局统一的处理方法没有体现。
    
     创建
     
      CustomerBlockHandler
     
     类用于自定义限流处理逻辑
    
   
public class CustomerBlockHandler
{
    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
    }
}
    
    
    在
    
     RateLimitController
    
    添加新的方法
   
     /**
     * 自定义通用的限流处理逻辑
     blockHandlerClass = CustomerBlockHandler.class
     blockHandler = handleException
     上述配置:找CustomerBlockHandler类里的handleException方法进行兜底处理
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客户自定义限流处理逻辑");
    }
    配置进一步说明
    
     
   
    启动微服务后先访问一次
    
     http://localhost:8401/rateLimit/customerBlockHandler
    
    
    Sentinel控制台配置
    
    
    
    启动微服务后先疯狂访问
    
     http://localhost:8401/rateLimit/customerBlockHandler
    
    
     
   
    
    
    更多注解属性说明
   
    关于
    
     @SentinelResource
    
    注解最主要的两个用法:限流控制和熔断降级的具体使用案例介绍完了。另外,该注解还有一些其他更精细化的配置,比如忽略某些异常的配置、默认降级函数等等,具体可见如下说明:
   
- 
     
 value
 
 :资源名称,必需项(不能为空)
- 
     
 entryType
 
 :entry 类型,可选项(默认为 EntryType.OUT)
- 
     
 blockHandler / blockHandlerClass
 
 :
 
 blockHandle
 
 r对应处理
 
 BlockException
 
 的函数名称,可选项。
 
 blockHandler
 
 函数访问范围需要是
 
 public
 
 ,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为
 
 BlockException
 
 。
 
 blockHandler
 
 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
 
 blockHandlerClass
 
 为对应的类的
 
 Class
 
 对象,注意对应的函数必需为
 
 static
 
 函数,否则无法解析。
- 
     
 fallback
 
 :
 
 fallback
 
 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。
 
 fallback
 
 函数可以针对所有类型的异常(除了
 
 exceptionsToIgnore
 
 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:- 返回值类型必须与原函数返回值类型一致;
- 
       方法参数列表需要和原函数一致,或者可以额外多一个
 
 Throwable
 
 类型的参数用于接收对应的异常。
- 
       
 fallback
 
 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
 
 fallbackClass
 
 为对应的类的
 
 Class
 
 对象,注意对应的函数必需为 static 函数,否则无法解析。
 
- 
     
 defaultFallback(since 1.6.0)
 
 :默认的
 
 fallback
 
 函数名称,可选项,通常用于通用的
 
 fallback
 
 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了
 
 exceptionsToIgnore
 
 里面排除掉的异常类型)进行处理。若同时配置了
 
 fallback
 
 和
 
 defaultFallback
 
 ,则只有 fallback 会生效。defaultFallback 函数签名要求:- 返回值类型必须与原函数返回值类型一致;
- 
       方法参数列表需要为空,或者可以额外多一个
 
 Throwable
 
 类型的参数用于接收对应的异常。
- 
       
 defaultFallback
 
 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
 
- 
     
 exceptionsToIgnore
 
 (since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出
注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。
    特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException
    
     直接抛出
    
   
    
    
    服务熔断功能
   
- 
     
 sentinel整合ribbon+openFeign+fallback
 
- 
     
 启动nacos和sentinel
 
    
    
    创建服务提供者cloudalibaba-provider-payment9003/9004
   
- 
 新建cloudalibaba-provider-payment9003
 
 
   
- 
 修改pom文件,添加以下依赖
 
 <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.zhubayi.springcloud</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>
        <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>
- 
     
 添加
 
 application.yml
 
 配置文件
 
 
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
 
 
package com.zhubayi.springcloud.alibaba.controller;
import com.zhubayi.springcloud.entities.CommonResult;
import com.zhubayi.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;
    }
}
     
   
- 
     
 9004模块也是,要记得改端口号和启动类
 
    
    
    
    
    启动9003和9004以及nacos
    
    测试
    
     http://127.0.0.1:9003/paymentSQL/1
    
    
    
    
    测试
    
     http://127.0.0.1:9004/paymentSQL/1
    
    
     
   
    
    
    新建
    
     cloudalibaba-consumer-nacos-order84
    
    服务消费者模块
   
cloudalibaba-consumer-nacos-order84
- 
     
 修改pom文件,添加以下的依赖
 
<dependencies>
        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.zhubayi.springcloud</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>
        <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>
- 
     
 新建
 
 application.yml
 
 配置文件
 
server:
  port: 8400
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
- 
     
 启动类
 
 OrderNacosMain84
 
 
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}
    
    
    Ribbon系列
   
- 
     
 新建配置类
 
 ApplicationContextConfig
 
 ,向容器注入Bean
 
@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
- 
     
 controller
 
package com.zhubayi.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.zhubayi.springcloud.entities.CommonResult;
import com.zhubayi.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
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;
import java.sql.SQLException;
import java.util.concurrent.Executors;
@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端口,测试
    
     http://192.168.0.159:8400/consumer/fallback/1
    
    
    
    
    在刷新一下
    
     
   
    
    
    
     没有任何配置
    
   
    当访问
    
     http://192.168.0.159:8400/consumer/fallback/4
    
    
    
    
    
     给客户error页面,不友好
    
   
    
    
    
     只配置fallback
    
   
    
     修改controller,添加兜底方法
    
   
public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
    完整
    
     CircleBreakerController
    
    类
   
@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",fallback = "handlerFallback") //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;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }
}
    测试
    
    
    
    成功执行了兜底方法
   
    
    
    
     只配置blockHandler
    
   
    
     修改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",fallback = "handlerFallback") //fallback只负责业务异常 handlerFallback兜底方法
     @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 ("非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录");
        }
        return result;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
    }
    public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }
}
    添加流控规则
    
    
    
    疯狂访问
    
     http://192.168.0.159:8400/consumer/fallback/1
    
     
   
    
    
    
     fallback和blockHandler都配置
    
   
- 
     修改
 
 @SentinelResource
 
 注解
 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
    
     若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。fallback只负责业务异常 handlerFallback兜底方法,blockHandler负责在sentinel里面配置的降级限流
    
   
    
     忽略属性
    
   
 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class}) //exceptionsToIgnore忽略这个异常,就是这个异常不处理
     
   
    
    
    
     Feign系列
    
   
- pom文件记得添加openfeign的依赖
<!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
- 修改配置文件激活Sentinel对Feign的支持
# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true  
- 
     业务类
 
 IPaymentService
 
/**
 * 使用 fallback 方式是无法获取异常信息的,
 * 如果想要获取异常信息,可以使用 fallbackFactory参数
 */
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
public interface IPaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
 
    
     PaymentFallbackService
    
   
@Component
public class PaymentFallbackService implements IPaymentService{
    /**
     * 远程调用
     *
     * @param id
     * @return
     */
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(444,"服务降级返回",new Payment(id,"error"));
    }
}
    
     controller
    
   
//==================OpenFeign
//解决办法https://blog.csdn.net/kongliand/article/details/108058831
    @Resource
    private IPaymentService ipaymentService;
    @GetMapping(value = "/consumer/openfeign/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        if(id == 4)
        {
            throw new RuntimeException("没有该id");
        }
        return ipaymentService.paymentSQL(id);
    }
- 
     在主启动类上添加
 
 EnableFeignClients
 
 注解,开启远程调用
    测试:把9003、9004都关了,然后访问
    
     http://192.168.0.159:8400/consumer/openfeign/1
    
    
    
    
    成功进行了降级。
   
    
    
    
     规则持久化
    
   
- 
     
 一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化
 
- 
     
 将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台
 
 的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效
 
- 
     
 修改
 
 cloudalibaba-sentinel-service8401
 
 
- 
     
 添加依赖
 
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
- 
     
 修改配置文件
 
 
spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
    
     完整配置文件
    
   
 
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
      #sentinel持久化
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
management:
  endpoints:
    web:
      exposure:
        include: '*'
feign:
  sentinel:
    enabled: true # 激活Sentinel对Feign的支持
- 
     
 添加Nacos业务规则配置
 
 
  
 
 配置dataId、配置组和配置格式的由来
    
    
    配置说明:
   
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。
    启动8401后
    
     刷新sentinel
    
    发现业务规则有了
    
    
    
    
     测试
    
    
    快速访问测试接口
    
     http://192.168.0.159:8401/rateLimit/byUrl
    
    
    
    
    
     停止8401再看sentinel
    
    
    
    
    
     发现流控规则没有了,重新启动8401再看sentinel
    
    
    
     刚开始看还是没有,去访问
     
      http://192.168.0.159:8401/rateLimit/byUrl
     
     或者
     
      http://127.0.0.1:8401/rateLimit/byUrl
     
     ,重新配置出现了,持久化验证通过
    
   
 
