Spring Cloud Alibaba 之 Sentinel 集成限流

一、什么是 Sentinel?

Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。

二、Sentinel 入门

Sentinel 不算是个复杂的东西,集成起来很容易,但是我们需要理解其中的一些概念性东西。

  • 资源: 资源并不是一个很难理解的东西, 正如它的名字在可以理解为在 Sentinel 中,需要被 Sentinel 所管理不管是需要被限流还是熔断的接口都是资源
  • 规则: 规则即围绕不同的资源来制定不同的控制策略,在开发过程中,我们通过对不同的资源进行分类,从而达到因地制宜的效果。

三、官方文档

Sentinel-QuickStart

四、限流参数与规则

1. 限流参数

Field说明默认值
resource资源名,资源名是限流规则的作用对象
count限流阈值
grade限流阈值类型,QPS 或线程数模式QPS 模式
limitApp流控针对的调用来源default,代表不区分调用来源
strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
controlBehavior流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流直接拒绝

2. 限流规则

  • 拒绝策略: 顾名思义,超出限流的限制就直接抛异常
  • 冷启动策略: 通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。PS:用了下发现同样的超出阈值限制会抛异常,相信绝大部分系统都是应该尽量满足请求通过完成的,哪怕因为峰值要多等会儿,而不是抛异常,所以我选择下面那个策略。
  • 匀速启动策略配置: 这个策略可以让你的请求在 1S 内平均的匀速运行。举个栗子,假如定义 QPS=2,那么这个策略会将 1S 平均分为 2 个 500ms,每个 500ms 去运行一个请求。PS:注意配置队列中请求的等待时间,假如设置等待时间最长为 20s,那么你的请求最多可以在队列中等待 20s,期间一有空闲就可以顺序被执行而不是抛异常。默认值只有 500ms,所以一下就超时了,超时的时候就会抛异常。个人觉得这个是最符合绝大多数场景的策略。

三、集成

1. 引入依赖

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

2. 配置资源以及规则策略

/**
 * @author Jinpeng Lin
 * @description Sentinel 配置
 * @date 2022-03-21
 */
@Configuration
public class SentinelConfig {
	
	/**
     * 资源名
     */
	public static final String MY_RESOURCE = "my-resource"

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

    @PostConstruct
    public void sentinelConfig() {
        // 1.注册 熔断降级规则
        List<FlowRule> rules = Lists.newArrayList();
        rules.add(this.initFlowRules());
        // 限流管理器
        FlowRuleManager.loadRules(rules);
    }

    /**
     * 初始化倍罗限流规则
     * @return
     */
    private FlowRule initFlowRules() {
        FlowRule rule = new FlowRule();
        rule.setResource(SentinelConfig.MY_RESOURCE);
        // QPS 策略限制:RuleConstant.FLOW_GRADE_QPS
        // 线程策略限制:RuleConstant.FLOW_GRADE_THREAD
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置 QPS 数量
        rule.setCount(3);
        // 拒绝策略:RuleConstant.CONTROL_BEHAVIOR_DEFAULT
        // 冷启动策略:RuleConstant.CONTROL_BEHAVIOR_WARM_UP
        // 匀速启动策略:RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
        // 匀速启动策略配置:设置队列中请求的最大等待时长,默认只有 500毫秒,超出等待时长的失败
        rule.setMaxQueueingTimeMs(20 * 1000);
        // 冷启动策略配置:warmUpPeriodSec 代表期待系统进入稳定状态的时间(即预热时长)
        // rule.setWarmUpPeriodSec(10);
    }
}

3. 配置超时降级策略

  • 降级策略参数为被拦截接口参数的参数基础上,加一个异常参数
  • 降级的代码的返回值与被拦截接口返回值相同
/**
 * @author Jinpeng Lin
 * @description Sentinel 异常处理
 * @date 2022-03-22
 */
@Slf4j
public class SentinelExceptionHandler {

    /**
     * 限流降级
     * 限流规则:限流参数必须在被限流的接口上多个接收异常的参数,返回值必须与原接口相同
     * @param name
     * @param ex
     * @return
     */
    public static String exceptionHandler(String name, BlockException ex) {
        System.out.println(ex);
        return "请求失败了";
    }
}

4. 策略应用

@SentinelResource(value = SentinelConfig.MY_RESOURCE, blockHandler = "exceptionHandler", 
		blockHandlerClass = {SentinelExceptionHandler.class})
@GetMapping("/test/{name}")
public String test(@PathVariable("name") String name) {
    return "请求成功:" + name;
}