前言

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

熔断降级

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和Hystrix里面描述的问题是一样的。

注:上面我使用的是 linux 启动 sentinel,但是下面为了操作方便均在 windows 上演示

为了使得客户端接入控制台,需要:

  • 客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。您可以通过pom.xml引入 JAR 包
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.6</version>
</dependency>
  • 启动时加入 JVM 参数-Dcsp.sentinel.dashboard.server=consoleIp:port指定控制台地址和端口 (前面已经指定)。更多的参数参见启动参数文档。
  • 确保应用端有访问量

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。 使用 Sentinel 来进行熔断保护,主要分为几个步骤:

注:若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以通过 Spring 配置文件来指定配置,详情请参考Spring Cloud Alibaba Sentinel 文档

定义资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,RPC 接口方法,甚至可以是一段代码。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

把需要控制流量的代码用 Sentinel的关键代码 SphU.entry(“资源名”) 和 entry.exit() 包围起来即可。

导入依赖

<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2022.0.0.0</version>
</dependency>

配置 application.yml

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8849   #sentinel控制台的请求地址

@SentinelResource 注解

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

@SentinelResource用于定义资源,并提供可选的异常处理和 fallback 配置项。@SentinelResource注解包含以下属性:

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT)
  • blockHandler / blockHandlerClass

定义规则

规则主要有流控规则、 熔断降级规则、系统规则、权限规则、热点参数规则等

硬编码方式定义系统规则

private void initSystemRule() {
    List<SystemRule> rules = new ArrayList<>();
    SystemRule rule = new SystemRule();
    rule.setHighestSystemLoad(10);
    rules.add(rule);
    SystemRuleManager.loadRules(rules);
}

加载不同规则

FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则
SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则
AuthorityRuleManager.loadRules(List<AuthorityRule> rules); // 修改授权规则

官方 demo:Sentinel/sentinel-demo at master · alibaba/Sentinel (github.com)

基础示例 demo

熔断降级

在 sentinel 中熔断策略分为慢调用比例 (SLOW_REQUEST_RATIO),异常比例 (ERROR_RATIO),异常数 (ERROR_COUNT)

异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效

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 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

慢调用比例熔断 demo

具体应用

下面将会在 springboot 中使用配置文件配置规则

application. yml 配置流控和降级规则文件位置

spring:  
  application:  
    name: lin-cms-spring-boot  
  cloud:  
    sentinel:  
      datasource:  
        ds1:  
          file:  
            data-type: json  
            file: 'classpath: flowrule.json'  
            rule-type: flow  
        ds2:  
          file:  
            data-type: json  
            file: 'classpath: degraderule.json'  
            rule-type: degrade  
      # 立即加载  
      eager: true  
      transport:  
        dashboard: localhost:8849   #sentinel控制台的请求地址

然后配置规则

flowrule.json

[
  {
    "resource": "getBook",
    "controlBehavior": 0,
    "count": 5,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
  }
]

degraderule.json

[  
  {  
    "resource": "getBooks",  
    "limitApp": "default",  
    "grade": 0,  
    "count": 20,  
    "slowRatioThreshold": 0.5,  
    "minRequestAmount": 5,  
    "statIntervalMs": 1000,  
    "timeWindow": 10  
  }  
]

具体规则及参数说明请看[该文档](circuit-breaking | Sentinel (sentinelguard.io))

参数对应常量值可以参考 RuleConstant,该类位于 com.alibaba.csp.sentinel.slots.block

public final class RuleConstant {
 
    public static final int FLOW_GRADE_THREAD = 0; //限流 基于线程数 
    public static final int FLOW_GRADE_QPS = 1; //限流 基于QPS
 
    public static final int DEGRADE_GRADE_RT = 0; //降级 代表一秒内该资源的平均响应时间 
    /**
     * Degrade by biz exception ratio in the current {@link IntervalProperty#INTERVAL} second(s).
     */
    public static final int DEGRADE_GRADE_EXCEPTION_RATIO = 1; // 降级 异常比例
    /**
     * Degrade by biz exception count in the last 60 seconds.
     */
    public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2;// 降级, 异常数
 
    public static final int AUTHORITY_WHITE = 0;// 认证, 白名单
    public static final int AUTHORITY_BLACK = 1;// 认证, 黑名单
 
    public static final int STRATEGY_DIRECT = 0; // 根据调用方限流策略
    public static final int STRATEGY_RELATE = 1; // 关联流量限流策略
    public static final int STRATEGY_CHAIN = 2; // 根据调用链入口限流策略
 
    public static final int CONTROL_BEHAVIOR_DEFAULT = 0;// 限流行为,直接拒绝
    public static final int CONTROL_BEHAVIOR_WARM_UP = 1;// 限流行为,WARM_UP 
    public static final int CONTROL_BEHAVIOR_RATE_LIMITER = 2;// 限流行为,匀速排队
    public static final int CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER = 3;
 
    public static final String LIMIT_APP_DEFAULT = "default";
    public static final String LIMIT_APP_OTHER = "other";
 
    public static final int DEFAULT_SAMPLE_COUNT = 2;
    public static final int DEFAULT_WINDOW_INTERVAL_MS = 1000;
 
    private RuleConstant() {}
}

然后使用 Apifox 或是 JMeter 进行流控测试,可以看到 QPS 流控生效

微服务