gateway sentinel 熔断 不起作用_Sentinel实现熔断与限流 - 魔笔钨丝浣

学习地址:https://www.bilibili.com/video/BV18E411x7eT?p=111

Sentinel

官网地址:

中文文档:/wiki/介绍

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

解决服务使用中的各种问题:服务雪崩、服务降级、服务熔断、服务限流。

主要特性

f156d95af87652cc3678732450529ed2.png

相关配置:

安装

下载地址:/releases

演示版本:

前提:java8

8080端口不能被占用

Sentinel分为两个部分:

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

  2. 控制台(Dashboard) 基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

运行

java -jar .jar

http://localhost:8080
登录账号密码均为sentinel

08c626ebd066696dc2c4b72c48231afe.png


dac35357865685a53e1594beb653790a.png


c3fd1beeee0f05e9792d8889cd78c4f1.png

初始化演示工程

启动Nacos8848成功

http://localhost:8848/nacos/#/login

cloudalibaba-sentinel-service8401

  1. 建module

  2. 写POM

<?xml version="" encoding="UTF-8"?>
<project xmlns=""
         xmlns:xsi=""
         xsi:schemaLocation=" http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud2020</artifactId>
        <groupId>com.nuc.springcloud</groupId>
        <version>-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <dependencies>
        <dependency>
            <groupId>com.nuc.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${}</version>
        </dependency>

        <dependency>
            <groupId>com.nuc.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${}</version>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

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

        <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>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</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>
  1. 写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
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
    public static void main(String[] args) {
        ();
    }
}
  1. 业务类
@RestController
@Slf4j
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}
  1. 测试

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

Sentinel采用的懒加载:执行一次访问即可

64c03e27da4c200071203b63bcc2be76.png


e746a12c027340ae2b32fe1560d275fa.png

流控规则

资源名:唯一名称,默认请求路径

针对来源:Sentine可以针对调用者进行限流,填写微服务名,默认default (不区分来源)

阈值类型/单机阈值:
QPS (每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
线程数:当调用该api的线程数达到阈值的时候,进行限流

是否集群:不需要集群

流控模式:
直接:api达到限流条件时,直接限流
关联:当关联的资源达到阈值时,就限流自己
链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)[api级别的针对来源]

流控效果:
快速失败:直接失败,抛异常
Warm Up:根据codeFactor (冷加载因子,默认3)的值,从阈值 / codeFactor,经过预热时长,才达到设置的QPS阈值
排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,则无效

流控模式

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

2d85310e11dd718e3023a14bbfafb3c7.png


表示一秒内查询1次就OK,若超过次数1,就直接--快速失败,报默认错误

a3583ac932b607c24ee565fa69914688.png

思考:需要一个类似fallback的兜底方法

关联

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

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

B惹事,A挂了

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

e43a174d9bbd23fb72a1ab29b80b036b.png


手动测试

02917d8983a043e3d0f5ad17d4a3c9ae.png


postman测试线程数访问

访问testB成功

233191c991f16841d29b9376e8f121aa.png


postman里新建多线程集合组

49c861d40074d91a17591d8b5ebcee8b.png


将访问地址添加进新线程组

874a00aa1eb616b63cdad86d42cfbf59.png


20个线程每次间隔秒访问一次

e56b8f782ccd2ef98af3878d05b83268.png


大批量线程高并发访问B,导致A失效了

11ef957f69837008c707187c88991451.png

链路

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

NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。

a9b4f1c497b20dfdec3a44ebe25f3273.png

上图中来自入口 Entrance1Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategy,同时设置 refResourceEntrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。

流控效果

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

直接失败,抛出异常Blocked by Sentinel (flow limiting)

预热

官网地址:/wiki/限流---冷启动

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

案例:阈值为10 + 预热时长设置5秒

系统初始化的阈值为10 / 3 约等于3,即阈值刚开始为3;然后过了5秒后阈值才慢慢恢复到10

14162c6e1ee317c9de524cf9dad7efea.png


测试:

多次点击http://localhost:8401/testB
刚开始不行,后续慢慢OK

应用:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值

排队等待

匀速排队()方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

该方式的作用如下图所示:

6c25cf54250d29405adf10987717d39b.png

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

注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

cc46c6d4af8c881a50de468957b049bc.png


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

降级规则

官网地址:/wiki/熔断降级

模式

  1. RT (平均响应时间,秒级)
  • 平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级

  • 窗口期过后关闭断路器

  • RT最大4900 (更大的需要通过才能生效)

  1. 异常比列(秒级)
  • QPS>= 5且异常比例(秒级统计)超过阈值时,触发降级;时间窗门结束后,关闭降级
  1. 异常数(分钟级)
  • 异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

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

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

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

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

3d6bb3dc709c2de955010b1262cf9c6d.png

慢调用比例

慢调用比例(SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

1e92b3f17514bb8e546ca549699ef2b4.png


@GetMapping("/testD")
public String testD() {
    try {
        (1);
    } catch (InterruptedException e) {
        ();
    }
    ("testD 测试RT");
    
    return "------testD";
}

e0d346cdbd8cd6b1cb7f4ba2496ac626.png


配置线程组

3f1ffd8a89c39b12c5a8fb7e7c0267c3.png


配置HTTP请求

1e3812a9437f676617e56c82a605e62e.png


jmeter测试

6ac03398bae4507ad42c47c9b89d4960.png


恢复

8d876734ac88ed0666c7948a921649b9.png


按照上述配置,永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用。

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

异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, ],代表 0% - 100%。

ad85744dbbe75ca18a343394fe4677ac.png


@GetMapping("/testD")
public String testD() {
    ("testD 异常比例");
    int age = 10/0;
    return "------testD";
}

3118caf9b11744a9a6cd27f28cb69858.png


使用Jmeter

0fecf4cce51e3a000214b074294695ba.png


单独访问一次

2c14fa0e83f990fd8d1cdb8bb4a7f2b8.png


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

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

异常数

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

d4205601475f3a71c7b4b78aa5481f2e.png


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

06e63a6cd15ad65dadd50ed3e6c4fe71.png


访问5次

a0b7d13972441450d7bb2cf1444f6ba5.png


第6次进入熔断降级

531479cdcdabd1f77dc5a13e5731cfdc.png


第一次访问绝对报错,因为除数不能为零到error窗口,但是到达5次后,进入熔断降级

热点key限流

官网地址:/wiki/热点参数限流

兜底方法
分为系统默认和客户自定义两种,之前的case,限流出问题后,都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting)

从HystrixCommand到@SentinelResource

@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";
}

d39d07e9ad158972c2f9960e54376686.png


http://localhost:8401/testHotKey?p1=abc

http://localhost:8401/testHotKey?p1=abc&p2=33

http://localhost:8401/testHotKey?p2=abc

d4d7ac13215594a335149b10b11457db.png


包含参数索引0的p1,当QPS超过1秒1次点击后马上被限流

特例设置

我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样

假如当p1的值等于5时,它的阈值可以达到200


1e02b1f620f2fd518d71cef543f61cb6.png


0b2bb8c42533226e83a501bfda6bd256.png


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

异常

@Sent inelResource
处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;

RuntimeException
int age = 10/0, 这个是java运行时报出的运行时异常RunTimeException,@SentinelResource不管

总结
@SentinelResource主管配置出错,运行出错该走异常走异常

b833a0821944dad01bbe2d0a180a31ef.png

解决:稍后

系统自适应限流

官方地址:/wiki/系统自适应限流

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores *
  • CPU usage( 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

7c7f2da9f311b628ffe77f6ce0a5875f.png

@SentinelResource

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

业务类

@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, ().getCanonicalName() + "\t 服务不可用");
    }
}

配置流控规则

14e83b73d9933472eadb40407e95e282.png


1秒钟点击1下,OK

c2ddae08bcf5d63e57426dac8a71609a.png


疯狂点击,返回了自己定义的限流处理信息,限流发送

97282911bb8792ec7e4b0ed8f0db2a73.png


此时关闭微服务8401看看

Sentinel控制台,流控规则消失了?????临时 --> 下文持久化解决

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

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

业务类

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

配置流控规则

21ffb5ad0dbd5dabbe954ede37cc03cc.png


一次

eb769beebbdee99677d671045fde9a61.png


32fd0df931d65f586665592a277904bb.png


系统默认的,没有体现我们自己的业务要求。
依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
每个业务方法都添加一个兜底的,那代码膨胀加剧。
全局统一的处理方法没有体现。

客户自定义限流处理逻辑

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

业务层

public class CustomerBlockHandler {
    public static CommonResult handlerException(BlockException exception) {
        return new CommonResult(4444, "按客戶自定义,global handlerException----1");
    }

    public static CommonResult handlerException2(BlockException exception) {
        return new CommonResult(4444, "按客戶自定义,global handlerException----2");
    }
}
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
        blockHandlerClass = CustomerBlockHandler.class,
        blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
    return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}

0acb583879057b0af4d36318b6e0184e.png


03b2dcca55c7e7c4f8503f263ae855d4.png


a31206c1feb308a3ddbc8ea895ebed81.png


d704b939b1532d7871a9bc80e4a88943.png


Sentinel主要有三个核心API

SphU定义资源

Tracer定义统计

ContextUtil定义了上下文

服务熔断功能

sentinel整合ribbon+openFeign+fallback

cloudalibaba-provider-payment9003/9004

  1. 建module

  2. 写POM

<?xml version="" encoding="UTF-8"?>
<project xmlns=""
         xmlns:xsi=""
         xsi:schemaLocation=" http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud2020</artifactId>
        <groupId>com.nuc.springcloud</groupId>
        <version>-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-provider-payment9003</artifactId>

    <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.nuc.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <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>

</project>
  1. 写YML
server:
  port: 9003

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

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        ();
    }
}
  1. 业务类
@RestController
public class PaymentController {
    @Value("${}")
    private String serverPort;

    public static HashMap<Long, Payment> hashMap = new HashMap<>();

    static {
        (1L, new Payment(1L, "28a8c1e3bc2742d8848569891fb42181"));
        (2L, new Payment(2L, "bba8c1e3bc2742d8848569891ac32182"));
        (3L, new Payment(3L, "6ua8c1e3bc2742d8848569891xt92183"));
    }

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

}
  1. 测试

6734e57e7ea295e26c7265b898e7d9a4.png


类似的新建9004,注意修改port

cloudalibaba-consumer-nacos-order84

  1. 建module

  2. 写POM

<?xml version="" encoding="UTF-8"?>
<project xmlns=""
         xmlns:xsi=""
         xsi:schemaLocation=" http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud2020</artifactId>
        <groupId>com.nuc.springcloud</groupId>
        <version>-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.nuc.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${}</version>
        </dependency>
        <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>
        <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>
  1. 写YML
server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

service-url:
  nacos-user-service: http://nacos-payment-provider
  1. 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderNacosMain84 {
    public static void main(String[] args) {
        ();
    }
}
  1. 业务类
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
@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 = {})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = (SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (() == 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内容  " + (), payment);
    }

    //blockHandler
    public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + (), payment);
    }
    
}

Ribbon系列

controller

fallback管运行异常

blockHandler管配置违规

无任何配置

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback")
public CommonResult<Payment> fallback(@PathVariable Long id){}

040ca3e862ce59256babd2b5352511f3.png


3af7fff8d3d4c329d1e303b8a617ef8e.png


只配置fallback

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
public CommonResult<Payment> fallback(@PathVariable Long id) {}

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

219f247803e194b960fb0f27a0a7b60f.png


e7cb6ac260fbff256d4db23feb28f7ab.png

只配置blockHandler

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
public CommonResult<Payment> fallback(@PathVariable Long id) {}

//blockHandler
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    Payment payment = new Payment(id, "null");
    return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + (), payment);
}

c81269f326d9764c20371be94dc645f3.png


第一次

fbbe26aa295ec2e7b7e282eb31a6ea69.png


1ec0bb95045066db37d3682101acce80.png

fallback和blockHandler都配置

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id){}

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

//blockHandler
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    Payment payment = new Payment(id, "null");
    return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + (), payment);
}

fbdb8021829db895cd78be096405a33e.png


4f51c7e5840ff8127262b65ff342ec24.png


8837f67c72d2bc99e16ebd1c4d53ad86.png


4dd09a267b74edbde7a406eea06119a4.png


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

忽略属性

@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
                  exceptionsToIgnore = {})
public CommonResult<Payment> fallback(@PathVariable Long id) {}

ef33f3ec7382337a53fcfaae1817bd02.png


4e5f400cc21661ed3203fb9e8f35f0d4.png


af55750b096c2eb412c788bbc7ba3a3b.png

Feign系列

84

POM

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

改YML

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

业务类

@FeignClient(value = "nacos-payment-provider", fallback = )
public interface PaymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}
public class CircleBreakerController {
	// OpenFeign
    @Resource
    private PaymentService paymentService;

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

主启动类

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84{}

测试

cc576132b8d773729a42e3df81c2c443.png


关闭9003/9004,自动降级

7177b0a4aaac301e4cd67197a51960dc.png


熔断框架比较

SentinelHystrixresilience4j
隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离
信号量隔离基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间
实时统计实现滑动窗口(LeapArray)滑动窗口(基于RxJava)Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点.插件的形式接口的形式.
基于注解的支持支持支持支持
限流基于QPS.支持基于调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式不支持简单的Rate Limiter模式
系统自适应保护支持不支持不支持
控制台提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等简单的监控查看不提供控制台,可对接其它监控系统

规则持久化

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

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

8401

POM

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

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
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
      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的支持
  
[
    {
         "resource": "/rateLimit/byUrl",
         "limitApp": "default",
         "grade": 1,
         "count": 1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
]

359f9a295692443f0836d009909b4622.png


003ed22e19a5840ff87aa0037e86bf8d.png


测试

268a31da01790fe1d6256125b4e008de.png


http://localhost:8401/rateLimit/byUrl

9a41d458f6ced9073563d6e702c8385d.png


重启8401,依旧生效,持久化成功。