阿里双11同款,流量防卫兵 Sentinel go 源码解读( 二 )

TrafficShapingCalculator 接口用于计算限流的上限 , 如果不使用 warm-up 功能 , 可以不去深究其实现 , 其实体之一 DirectTrafficShapingCalculator 返回 Rule.Threshold【用户设定的限流上限】 。
// TrafficShapingChecker performs checking according to current metrics and the traffic// shaping strategy, then yield the token result.type TrafficShapingChecker interface {DoCheck(resStat base.StatNode, acquireCount uint32, threshold float64) *base.TokenResult}type RejectTrafficShapingChecker struct {rule*Rule}func (d *RejectTrafficShapingChecker) DoCheck(resStat base.StatNode, acquireCount uint32, threshold float64) *base.TokenResult {metricReadonlyStat := d.BoundOwner().boundStat.readOnlyMetricif metricReadonlyStat == nil {return nil}curCount := float64(metricReadonlyStat.GetSum(base.MetricEventPass))if curCount+float64(acquireCount) > threshold {return base.NewTokenResultBlockedWithCause(base.BlockTypeFlow, "", d.rule, curCount)}return nil}RejectTrafficShapingChecker 依据 Rule.Threshold 判定 Resource 在当前时间窗口是否超限 , 其限流结果 TokenResultStatus 只可能是 Pass 或者 Blocked 。
sentinel flow 还有一个匀速限流 ThrottlingChecker , 它的目的是让请求匀速被执行 , 把一个时间窗口【譬如 1s】根据 threshold 再细分为更细的微时间窗口 , 在每个微时间窗口最多执行一次请求 , 其限流结果 TokenResultStatus 只可能是 Pass 或者 Blocked 或者 Wait , 其相关意义分别为:

  • Pass:在微时间窗口内无超限 , 请求通过;
  • Wait:在微时间窗口内超限 , 被滞后若干时间窗口执行 , 在这段时间内请求需要等待;
  • Blocked:在微时间窗口内超限 , 且等待时间超过用户设定的最大愿意等待时间长度【Rule.MaxQueueingTimeMs】 , 请求被拒绝 。
type TrafficShapingController struct {flowCalculator TrafficShapingCalculatorflowCheckerTrafficShapingCheckerrule *Rule// boundStat is the statistic of current TrafficShapingControllerboundStat standaloneStatistic}func (t *TrafficShapingController) PerformChecking(acquireCount uint32, flag int32) *base.TokenResult {allowedTokens := t.flowCalculator.CalculateAllowedTokens(acquireCount, flag)return t.flowChecker.DoCheck(resStat, acquireCount, allowedTokens)}在 Direct + Reject 限流的场景下 , 这三个接口其实并无多大意义 , 其核心函数 TrafficShapingController.PerformChecking() 的主要流程是:
  • 1 从 TrafficShapingController.boundStat 中获取当前 Resource 的 metrics 值【curCount】;
  • 2 如果 curCount + batchNum(acquireCount) > Rule.Threshold , 则 pass , 否则就 reject 。
在限流场景下 ,TrafficShapingController 四个成员的意义如下:
  • flowCalculator 计算限流上限;
  • flowChecker 执行限流 Check 动作;
  • rule 存储限流规则;
  • boundStat 存储限流的 Check 结果和时间窗口参数 , 作为下次限流 Check 动作判定的依据 。
1.4.2 TrafficControllerMap
在执行限流判定时 , 需要根据 Resource 名称获取其对应的 TrafficShapingController 。
// TrafficControllerMap represents the map storage for TrafficShapingController.type TrafficControllerMap map[string][]*TrafficShapingController// core/flow/rule_manager.gotcMap= make(TrafficControllerMap)package 级别全局私有变量 tcMap 存储了所有的 Rule , 其 key 为 Resource 名称 , value 则是与 Resource 对应的 TrafficShapingController 。
用户级别接口函数 core/flow/rule_manager.go:LoadRules() 会根据用户定义的 Rule 构造其对应的 TrafficShapingController 存入 tcMap , 这个接口调用函数 generateStatFor(*Rule) 构造 TrafficShapingController.boundStat 。
限流场景下 , 函数 generateStatFor(*Rule) 的核心代码如下:
func generateStatFor(rule *Rule) (*standaloneStatistic, error) {resNode = stat.GetOrCreateResourceNode(rule.Resource, base.ResTypeCommon)// default case, use the resource's default statisticreadStat := resNode.DefaultMetric()retStat.reuseResourceStat = trueretStat.readOnlyMetric = readStatretStat.writeOnlyMetric = nilreturn--tt-darkmode-color: #6A737D;">1 BucketWrap
【阿里双11同款,流量防卫兵 Sentinel go 源码解读】时间轮的最基本单元是一个桶【时间窗口】 。
// BucketWrap represent a slot to record metrics// In order to reduce the usage of memory, BucketWrap don't hold length of BucketWrap// The length of BucketWrap could be seen in LeapArray.// The scope of time is [startTime, startTime+bucketLength)// The size of BucketWrap is 24(8+16) bytestype BucketWrap struct {// The start timestamp of this statistic bucket wrapper.BucketStart uint64// The actual data structure to record the metrics (e.g. MetricBucket).Value atomic.Value}补充:这里之所以用指针 , 是因为以 BucketWrap 为基础的 AtomicBucketWrapArray 会被多个 sentinel 流控组件使用 , 每个组件的流控参数不一 , 例如: