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


阿里双11同款,流量防卫兵 Sentinel go 源码解读文章插图
导读:本文主要分析阿里巴巴集团开源的流量控制中间件 Sentinel , 其原生支持了 Java/Go/C++ 等多种语言 , 本文仅仅分析其 Go 语言实现 。 下文如无特殊说明 , sentinel 指代 Sentinel-Go 。
1 基本概念 Resource 和 Rule1.1 Resource
// ResourceType represents classification of the resourcestype ResourceType int32const (ResTypeCommon ResourceType = iotaResTypeWebResTypeRPC)// TrafficType describes the traffic type: Inbound or Outboundtype TrafficType int32const (// Inbound represents the inbound traffic (e.g. provider)Inbound TrafficType = iota// Outbound represents the outbound traffic (e.g. consumer)Outbound)// ResourceWrapper represents the invocationtype ResourceWrapper struct {// global unique resource namename string// resource classificationclassification ResourceType// Inbound or OutboundflowType TrafficType}Resource(ResourceWrapper) 存储了应用场景 ResourceType , 以及目标流控的方向 FlowType(TrafficType) 。
1.2 Entry
// EntryOptions represents the options of a Sentinel resource entry.type EntryOptions struct {resourceType base.ResourceTypeentryTypebase.TrafficTypeacquireCount uint32slotChain*base.SlotChain}type EntryContext struct {entry *SentinelEntry// Use to calculate RTstartTime uint64Resource *ResourceWrapperStatNode StatNodeInput *SentinelInput// the result of rule slots checkRuleCheckResult *TokenResult}type SentinelEntry struct {res *ResourceWrapper// one entry bounds with one contextctx *EntryContextsc *SlotChain}Entry 实体 SentinelEntry 关联了 Resource(ResourceWrapper) 以及其流控规则集合 SlotChain 。 每个 Entry 实体有一个上下文环境 EntryContext , 存储每个 Rule 检测时用到的一些流控参数和流控判定结果 。
值得注意的是 , SentinelEntry.sc 值来自于 EntryOptions.slotChain , EntryOptions.slotChain 存储了全局 SlotChain 对象 api/slot_chain.go:globalSlotChain 。
至于何为 SlotChain , 就是 sentinel 提供的所有的流控组件的集合 , 可以简单地认为每个流控组件就是一个 Slot , 其详细分析见[[3.5 SlotChain]](#3.5) 。
sentinel 一些变量和函数命名的可读性较差 , 如 EntryOptions.acquireCount 实在无法让人望文生义 , 看过函数 core/api.go:WithAcquireCount() 的注释才明白:EntryOptions.acquireCount 是批量动作执行次数 。 如有的一次 RPC 请求中调用了服务端的一个服务接口 , 则取值 1【也是 EntryOptions.acquireCount 的默认取值】 , 如果调用了服务端的 3 个服务接口 , 则取值 3 。 所以建议改名为 EntryOptions.batchCount 比较好 , 考虑到最小改动原则 , 可以在保留 core/api.go:WithAcquireCount() 的同时增加一个同样功能的 core/api.go:WithBatchCount() 接口 。 相关改进已经提交到 pr 263 。
1.3 Rule
type TokenCalculateStrategy int32const (Direct TokenCalculateStrategy = iotaWarmUp)type ControlBehavior int32const (Reject ControlBehavior = iotaThrottling)// Rule describes the strategy of flow control, the flow control strategy is based on QPS statistic metrictype Rule struct {// Resource represents the resource name.Resourcestring`json:"resource"`ControlBehaviorControlBehavior`json:"controlBehavior"`// Threshold means the threshold during StatIntervalInMs// If StatIntervalInMs is 1000(1 second), Threshold means QPSThresholdfloat64`json:"threshold"`MaxQueueingTimeMs uint32`json:"maxQueueingTimeMs"`// StatIntervalInMs indicates the statistic interval and it's the optional setting for flow Rule.// If user doesn't set StatIntervalInMs, that means using default metric statistic of resource.// If the StatIntervalInMs user specifies can not reuse the global statistic of resource,//sentinel will generate independent statistic structure for this rule.StatIntervalInMs uint32 `json:"statIntervalInMs"`}Rule 记录了某 Resource 的限流判定阈值 Threshold、限流时间窗口计时长度 StatIntervalInMs 以及 触发限流后的判罚动作 ControlBehavior 。
上面核心是 Rule 的接口 RuleCheckSlot , 至于 StatSlot 则用于统计 sentinel 自身的运行 metrics 。
1.4 Flow
当前章节主要分析流控中的限流(core/flow) , 根据流控的处理流程梳理 sentinel 整体骨架 。
1.4.1 TrafficShapingController
所谓 TrafficShapingController , 顾名思义 , 就是 流量塑形控制器 , 是流控的具体实施者 。
// core/flow/traffic_shaping.go// TrafficShapingCalculator calculates the actual traffic shaping threshold// based on the threshold of rule and the traffic shaping strategy.type TrafficShapingCalculator interface {CalculateAllowedTokens(acquireCount uint32, flag int32) float64}type DirectTrafficShapingCalculator struct {threshold float64}func (d *DirectTrafficShapingCalculator) CalculateAllowedTokens(uint32, int32) float64 {return d.threshold}