1 什么是Sentinel

Sentinel,中文翻译为哨兵,是为微服务提供流量控制、熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的“雪崩”效应,为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维护期,不再提供新功能,Sentinel是一个不错的替代方案。通常情况,Hystrix采用线程池对服务的调用进行隔离,Sentinel才用了用户线程对接口进行隔离,二者相比,Hystrxi是服务级别的隔离,Sentinel提供了接口级别的隔离,Sentinel隔离级别更加精细,另外Sentinel直接使用用户线程进行限制,相比Hystrix的线程池隔离,减少了线程切换的开销。另外Sentinel的DashBoard提供了在线更改限流规则的配置,也更加的优化。

从官方文档的介绍,Sentinel 具有以下特征:

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

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

广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring

Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

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

2 Sentinel控制台

Sentinel控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能. Sentinel DashBoard下载地址:https://github.com/alibaba/Sentinel/releases

下载完成后,以以下的命令启动

# 此处修改默认端口为18080
java -Dserver.port=18080 -Dcsp.sentinel.dashboard.server=localhost:18080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

启动成功后,在浏览器上访问localhost:18080,就可以显示Sentinel的登陆界面,登陆名为sentinel,密码为sentinel。
需要访问一次注册的服务才能显示出来,因为Sentinel是懒加载的;

2 如何在Spring Cloud中使用Sentinel

Sentinel作为Spring Cloud Alibaba的组件之一,在Spring Cloud项目中使用它非常的简单。现在以案例的形式来讲解如何在Spring

Cloud项目中使用Sentinel。本项目是在之前教程的案例基础上进行改造。在工程的pom文件加上sentinel的Spring

Cloud起步依赖,代码如下:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

在工程的配置文件application.yml文件中配置,需要新增2个配置:

spring.cloud.sentinel.transport.port: 8719 ,这个端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。

spring.cloud.sentinel.transport.dashboard: 8080,这个是SentinelDashBoard的地址。

spring
    sentinel:
      transport:
        port: 18720	# 交互端口,默认8719 占用可往上+1,直到可用
        dashboard: localhost:18080  #控制台实际启动的地址

此时调用接口就可用在Sentinel控制台看到
1647417283
需要注意的是,被限流的时候FeignClient并不会调用provider的接口,而是在consumer工程里直接报错。

3 配置限流

代码中配置限流

没有控制台上面配置的灵活,此处只了解一下用法,不去深究

    public static void main(String[] args) {
        // 配置规则.
        initFlowRules();
        while (true) {
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性,自动 exit entry
            try (Entry entry = SphU.entry("HelloWorld")) {
             // 被保护的逻辑
              System.out.println("hello world");
            } catch (BlockException ex) {
                // 处理被流控的逻辑
                System.out.println("blocked!");
            }
        }
    }

    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

控制台配置限流

1647417876

新增流控规则

1647418047

  • 资源名:唯一名称。默认为请求路径 @SentinelResource注解修饰时,取里面的value值
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名。默认default
  • QPS:每秒钟的请求数量,达到阈值进行限流
  • 线程数:请求线程数,达到阈值时限流
  • 直连:达到限流值直接限流
  • 关联:当关联资源达到阈值时限流自己
  • 链路:当某个接口过来的资源达到限流条件,触发限流
  • 快速失败:直接失败,抛出异常
  • Warm Up:根据codeFactor(冷加载因子,默认为3)的值,从阈值/codeFactor,经过预热时常,才达到设置的QPS阈值,避免突然大流量造成服务器的宕机!
  • 排队等待:匀速排队,让请求匀速通过,阈值为QPS才生效,其次还可以设置一个超时等待时间,超时将被抛弃
新增降级规则

1647419427

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断;
    • 比例阈值:慢调用统计数对于最小请求数的占有比例;
      注:比例阈值是Sentinel1.8.x版本的,如果比例阈值修改不生效/降级失败,需要将要将应用中的Sentinel的依赖改到相应的版本;
      关于Spring Cloud Alibaba 各组件的适配版本,参考:[https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E]
      比例阈值修改无效,参考:[https://github.com/alibaba/Sentinel/issues/1777]
    • 熔断时长:超过时间后会尝试恢复;
    • 最小请求数:触发熔断的最小请求数目,若当前统计窗口内的请求数小于此值,即使达到了熔断条件也不会触发;
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%;
    • 比例阈值:异常数对于最小请求数的占有比例;
    • 熔断时长:超过时间后会尝试恢复;
    • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断;
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断;
    • 异常数:统计的异常数;由于异常数是按照分钟统计的个数,时间窗口中的设置也必须要大于60s。不然会出现:结束熔断保护后仍可能继续熔断保护(不会释放!)
    • 熔断时长:超过时间后会尝试恢复;
    • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断;
新增热点规则

1647420569

  • 参数索引:对应controller中方法的下标,携带此参数的请求会被限流

  • 参数类型:方法中的参数类型

  • 参数值:上面的参数等于这个参数值时放宽规则

  • 限流阈值:参数等于参数值里面配置的值时的限流阈值

    注意配置完后点击添加

新增系统保护规则

1647421592

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

1647503031

  • 流控应用:微服务名称
  • 授权类型:白名单指只有上面配置的应用访问,黑名单只上面配置的应用不能访问

4 @SentinelResource

注意:注解方式不支持 private 方法。

@RestController
public class RateLimitController {
    //有兜底
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource() {
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }

    public CommonResult handleException(BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }
    
    //无兜底
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
}

有兜底的,按资源名配置:兜底方法优先
无兜底的通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息(直接抛出异常)
规律:
有兜底方法的按照资源名来,没有兜底方法的按照uri来
使用:只要使用了@SentinalResource 就配置一个兜底方法“BlockHandler”

触发异常产生的报错类型

Sentinel 限流降级本身的异常
BlockException
 
限流异常
FlowException
 
降级异常
DegradeException
 
参数限流异常
ParamFlowException
 
系统负载异常
SystemBlockException
 
授权异常
AuthorityException

关于@SentinelResource 注解,有以下的属性:

  • value:资源名称,必需项(不能为空)
  • entryType:entry类型,可选项(默认为 EntryType.OUT)
  • blockHandler 对应处理 BlockException 的函数名称,可选项。若同时配置了 fallback和 blockHandler ,则只有 blockHandler会生效。
    要求:
    • 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函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 defaultFallbackClass为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

5 Sentinel持久化

配置进nacos
pom

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

yml

spring
    sentinel:
      transport:
        port: 18720	# 交互端口,默认8719 占用可往上+1,直到可用
        dashboard: localhost:18080  #控制台实际启动的地址
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service # 配置文件信息
            groupId: DEFAULT_GROUP  # 配置文件信息
            data-type: json
            rule-type: flow

nacos添加配置
1647423987

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


resource:资源名称
limitApp:来源应用
grade:阀值类型,0-线程数,1-qps
count:单机阀值
strategy:流控模式,0-直接,1-关联,2-链路
controlBehavior:流控效果,0-快速失败,1-warm up,2-排队等待
clusterMode:是否集群

想要在控制台配置同步到nacos可以研究参考这篇文章
Sentinel1.8.0配置持久化到Nacos(基于push模式)

Q.E.D.