SpringCloud Sentinel 排队等待和Warm Up限流源码

WarmUp

WarmUp的原理是基于令牌桶算法,该算法存在一个"桶"来存放令牌,系统每一段时间就会往桶中存放一定数量的令牌。每一个请求会消耗一定数量的令牌,如果令牌足够,则该请求直接通过并消耗对应的令牌,否则则会拒绝该请求或者进行排队等待。

WarmUp的源码在com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

但直接看源码可能会很懵逼,可以先看一下这篇博客Sentinel中的冷启动限流算法 - 掘金 (juejin.cn)

根据这篇博客,我们可以知道WarmUp的基本原理:

  • 令牌产生速度与桶中的令牌数量成反比。也就是消耗越快,产生越快。
  • 在一开始,会把令牌桶赛满,之后请求通过后消耗令牌,并同时加快令牌生产速度。

这里有个问题,如果一个请求需要消耗大量令牌,那么不是可以瞬间导致令牌生产速度拉满?那么这里就是Sentinel的相关改进了。

首先通过构造器我们需要记住如下几个重要参数:

名称说明
count在控制台设置的QPS
coldFactor冷加载因子
warningToken预警令牌数量
maxToken令牌桶最大令牌数量
slope某个函数的斜率
warmUpPeriodInSec预热时间

有些写的很模糊,但是别急,我们先来看syncToken方法,这个方法是由canPass调用的:

protected void syncToken(long passQps) { // 获取当前时间 long currentTime = TimeUtil.currentTimeMillis(); // 将毫秒位设置为0 currentTime = currentTime - currentTime % 1000; // 获取上一次填充令牌桶的时间 long oldLastFillTime = lastFilledTime.get(); // 如果已经被别人改过了,就直接退出 if (currentTime <= oldLastFillTime) { return; } // 获取现有的令牌数量 long oldValue = storedTokens.get(); // 计算新的令牌数量 long newValue = coolDownTokens(currentTime, passQps); if (storedTokens.compareAndSet(oldValue, newValue)) { long currentValue = storedTokens.addAndGet(0 - passQps); if (currentValue < 0) { storedTokens.set(0L); } lastFilledTime.set(currentTime); } } private long coolDownTokens(long currentTime, long passQps) { // 获取现有的令牌数量 long oldValue = storedTokens.get(); long newValue = oldValue; // 当令牌的消耗程度远远低于警戒线的时候 // newValue = (已有令牌数量 + (时间间隔多少毫秒) * 每毫秒产生令牌的数量) if (oldValue < warningToken) { newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000); } else if (oldValue > warningToken) { // 到这里,说明还是冷启动阶段 if (passQps < (int)count / coldFactor) { newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000); } } return Math.min(newValue, maxToken); }
java