流量治理
Sentinel 流量治理
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel
是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,
从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel 历史
- 2012 年,
Sentinel
诞生,主要功能为入口流量控制。 - 2013-2017 年,
Sentinel
在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。 - 2018 年,
Sentinel
开源,并持续演进。 - 2019 年,
Sentinel
朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。 - 2020 年,推出
Sentinel Go
版本,继续朝着云原生方向演进。 - 2021 年,
Sentinel
正在朝着 2.0 云原生高可用决策中心组件进行演进;同时推出了Sentinel
Rust 原生版本。同时我们也在 Rust 社区进行了 Envoy WASM extension 及 eBPF extension 等场景探索。 - 2022 年,
Sentinel
品牌升级为流量治理,领域涵盖流量路由/调度、流量染色、流控降级、过载保护/实例摘除等;同时社区将流量治理相关标准抽出到 OpenSergo 标准中,Sentinel 作为流量治理标准实现。
Sentinel 功能和设计理念
流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
- Sentinel 的设计理念是让您自由选择控制的角度 ,并进行灵活组合,从而达到想要的效果。
熔断降级
什么是熔断降级
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
流量控制 (Sentinel Go)
流量控制(flow control
),其原理是监控资源(Resource
)的统计指标,然后根据 token
计算策略来计算资源的可用 token(也就是阈值),然后根据流量控制策略对请求进行控制,避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
Sentinel Go
的流量控制实现代码参考:https://github.com/alibaba/sentinel-golang/tree/master/core/flow
Sentinel
通过定义流控规则来实现对 Resource
的流量控制。在 Sentinel
内部会在加载流控规则时候将每个 flow.Rule 都会被转换成流量控制器(TrafficShapingController)。 每个流量控制器实例都会有自己独立的统计结构,这里统计结构是一个滑动窗口。Sentinel 内部会尽可能复用 Resource 级别的全局滑动窗口,如果流控规则的统计设置没法复用Resource的全局统计结构,那么Sentinel会为流量控制器创建一个全新的私有的滑动窗口,然后通过 flow.StandaloneStatSlot 这个统计Slot来维护统计指标。
流控规则
一条流控规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
-
Resource:资源名,即规则的作用目标。
-
TokenCalculateStrategy: 当前流量控制器的Token计算策略。Direct表示直接使用字段 Threshold 作为阈值;WarmUp表示使用预热方式计算Token的阈值。
-
ControlBehavior: 表示流量控制器的控制策略;Reject表示超过阈值直接拒绝,Throttling表示匀速排队。
-
Threshold: 表示流控阈值;如果字段 StatIntervalInMs 是1000(也就是1秒),那么Threshold就表示QPS,流量控制器也就会依据资源的QPS来做流控。
-
RelationStrategy: 调用关系限流策略,CurrentResource表示使用当前规则的resource做流控;AssociatedResource表示使用关联的resource做流控,关联的resource在字段 RefResource 定义;
-
RefResource: 关联的resource;
-
WarmUpPeriodSec: 预热的时间长度,该字段仅仅对 WarmUp 的TokenCalculateStrategy生效;
-
WarmUpColdFactor: 预热的因子,默认是3,该值的设置会影响 预热的速度,该字段仅仅对 WarmUp 的TokenCalculateStrategy生效;
-
MaxQueueingTimeMs: 匀速排队的最大等待时间,该字段仅仅对 Throttling ControlBehavior生效;
-
StatIntervalInMs: 规则对应的流量控制器的独立统计结构的统计周期。如果StatIntervalInMs是1000,也就是统计QPS。 这里特别强调一下 StatIntervalInMs 和 Threshold 这两个字段,这两个字段决定了流量控制器的灵敏度。以 Direct + Reject 的流控策略为例,流量控制器的行为就是在 StatIntervalInMs 周期内,允许的最大请求数量是Threshold。比如如果 StatIntervalInMs 是 10000,Threshold 是10000,那么流量控制器的行为就是控制该资源10s内运行最多10000次访问。
常见场景的规则配置
基于QPS对某个资源限流
基于对某个资源访问的QPS来做流控,这个是非常常见的场景。流控规则的配置下面有个sample:
{
"resource": "some-test",
"tokenCalculateStrategy": 0,
"controlBehavior": 1,
"threshold": 500,
"statIntervalInMs": 1000
}
基于一定统计间隔时间来控制总的请求数
这个场景就是想在一定统计周期内控制请求的总量。比如StatIntervalInMs配置10000,Threshold配置10000,这种配置意思就是控制10s内最大请求数是10000。sample:
{
"resource": "some-test",
"tokenCalculateStrategy": 0,
"controlBehavior": 1,
"threshold": 10000,
"statIntervalInMs": 10000
}
毫秒级别流控
针对一些流量曲在毫秒级别波动非常大的场景(类似于脉冲),建议StatIntervalInMs的配置在毫秒级别,除非特殊场景,建议配置的值为100ms的倍数,比如100,200这种。这种相当于缩小了统计周期,将QPS的周期缩小了10倍,控制周期降低到了100ms。这种配置能够很好的应对脉冲流量,保障系统稳定性,比如sample:
{
"resource": "some-test",
"tokenCalculateStrategy": 0,
"controlBehavior": 1,
"threshold": 80,
"statIntervalInMs": 100
}
熔断降级
// Rule encompasses the fields of circuit breaking rule.
type Rule struct {
// unique id
Id string `json:"id,omitempty"`
// resource name
Resource string `json:"resource"`
Strategy Strategy `json:"strategy"`
// RetryTimeoutMs represents recovery timeout (in milliseconds) before the circuit breaker opens.
// During the open period, no requests are permitted until the timeout has elapsed.
// After that, the circuit breaker will transform to half-open state for trying a few "trial" requests.
RetryTimeoutMs uint32 `json:"retryTimeoutMs"`
// MinRequestAmount represents the minimum number of requests (in an active statistic time span)
// that can trigger circuit breaking.
MinRequestAmount uint64 `json:"minRequestAmount"`
// StatIntervalMs represents statistic time interval of the internal circuit breaker (in ms).
StatIntervalMs uint32 `json:"statIntervalMs"`
// MaxAllowedRtMs indicates that any invocation whose response time exceeds this value (in ms)
// will be recorded as a slow request.
// MaxAllowedRtMs only takes effect for SlowRequestRatio strategy
MaxAllowedRtMs uint64 `json:"maxAllowedRtMs"`
// Threshold represents the threshold of circuit breaker.
// for SlowRequestRatio, it represents the max slow request ratio
// for ErrorRatio, it represents the max error request ratio
// for ErrorCount, it represents the max error request count
Threshold float64 `json:"threshold"`
}
- Id: 表示 Sentinel 规则的全局唯一ID,可选项。
- Resource: 熔断器规则生效的埋点资源的名称;
- Strategy: 熔断策略,目前支持SlowRequestRatio、ErrorRatio、ErrorCount三种; 选择以慢调用比例 (SlowRequestRatio) 作为阈值,需要设置允许的最大响应时间(MaxAllowedRtMs),请求的响应时间大于该值则统计为慢调用。通过 Threshold 字段设置触发熔断的慢调用比例,取值范围为 [0.0, 1.0]。规则配置后,在单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态,若接下来的一个请求响应时间小于设置的最大 RT 则结束熔断,若大于设置的最大 RT 则会再次被熔断。 选择以错误比例 (ErrorRatio) 作为阈值,需要设置触发熔断的异常比例(Threshold),取值范围为 [0.0, 1.0]。规则配置后,在单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态,若接下来的一个请求没有错误则结束熔断,否则会再次被熔断。代码中可以通过 api.TraceError(entry, err) 函数来记录 error。
- RetryTimeoutMs: 即熔断触发后持续的时间(单位为 ms)。资源进入熔断状态后,在配置的熔断时长内,请求都会快速失败。熔断结束后进入探测恢复模式(HALF-OPEN)。
- MinRequestAmount: 静默数量,如果当前统计周期内对资源的访问数量小于静默数量,那么熔断器就处于静默期。换言之,也就是触发熔断的最小请求数目,若当前统计周期内的请求数小于此值,即使达到熔断条件规则也不会触发。
- StatIntervalMs: 统计的时间窗口长度(单位为 ms)。
- MaxAllowedRtMs: 仅对慢调用熔断策略生效,MaxAllowedRtMs 是判断请求是否是慢调用的临界值,也就是如果请求的response time小于或等于MaxAllowedRtMs,那么就不是慢调用;如果response time大于MaxAllowedRtMs,那么当前请求就属于慢调用。
- Threshold: 对于慢调用熔断策略, Threshold表示是慢调用比例的阈值(小数表示,比如0.1表示10%),也就是如果当前资源的慢调用比例如果高于Threshold,那么熔断器就会断开;否则保持闭合状态。 对于错误比例策略,Threshold表示的是错误比例的阈值(小数表示,比如0.1表示10%)。对于错误数策略,Threshold是错误计数的阈值。
一些补充说明:
- Resource、Strategy、RetryTimeoutMs、MinRequestAmount、StatIntervalMs、Threshold 每个规则都必设的字段,MaxAllowedRtMs是慢调用比例熔断规则必设的字段。
- MaxAllowedRtMs 字段仅仅对慢调用比例 (SlowRequestRatio) 策略有效,对其余策略均属于无效字段。
- StatIntervalMs 表示熔断器的统计周期,单位是毫秒,这个值我们不建议设置的太大或则太小,一般情况下设置10秒左右都OK,当然也要根据实际情况来适当调整。
- RetryTimeoutMs 的设置需要根据实际情况设置探测周期,一般情况下设置10秒左右都OK,当然也要根据实际情况来适当调整。
并发隔离控制
并发隔离控制是指基于资源访问的并发协 程数来控制对资源的访问,这里的思路和信号量隔离很类似,主要是控制对资源访问的最大并发数,避免因为资源的异常导致协程耗尽。
参考:https://github.com/alibaba/sentinel-golang/tree/master/core/isolation
隔离规则
并发隔离规则的定义如下:
// Rule describes the concurrency num control, that is similar to semaphore
type Rule struct {
// ID represents the unique ID of the rule (optional).
ID string `json:"id,omitempty"`
Resource string `json:"resource"`
MetricType MetricType `json:"metricType"`
Threshold uint32 `json:"threshold"`
}
Sentinel 支持 Concurrency,也就是并发数作为统计指标。如果资源当前的并发数高于阈值 (Threshold),那么资源将不可访问。
隔离规则配置示例(具体数值不作为线上配置参考,要根据业务系统情况而定):
{
"resource": "abc",
"metricType": 0,
"threshold": 100
}
系统自适应流控
Sentinel 系统自适应流控从整体维度对应用入口流量进行控制,结合系统的 Load、CPU 使用率以及应用的入口 QPS、平均响应时间和并发量等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是单个调用维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(埋点的 TrafficType 为 Inbound),比如 Web 服务或 gRPC provider 接收的请求,都属于入口流量。
系统自适应保护的原理参考 此处文档。
示例
{
"resource": "abc",
"metricType": 0,
"triggerCount": 80,
"strategy": 1
}
字段含义:
- resource: 资源名称
- metricType: 触发指标类型 0: 系统负载 1:所有入口流量平均应答时间 2:并发数 3:入口流量QPS 4:系统CPU使用率
- triggerCount: 触发阈值
- strategy: 策略 -1:无 1:TCP BBR
热点参数流控
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
Sentinel 通过埋点的形式,在每次 Entry(opts) 的时候携带上需要流控的参数。具体可以参考:api/api.go/#func WithArgs(args ...interface) EntryOption 函数
WithArgs 函数携带的是一个参数列表。Sentinel 的热点参数流控的每个规则会对参数列表中某一位置的参数生效(根据热点参数流控规则中的参数列表 ParamIndex 属性来指定生效参数位置)。Sentinel 会为每个规则都创建独立的统计结构,统计结构会缓存对应参数列表的 ParamIndex 的所有值,根据值的统计做流控。
这里举个例子:假设每次 Entry 的时候携带上的参数的类型列表是:[string, int]。现在有一个规则 R1 在 ParamIndex 是 0 的位置生效,规则基于并发数去做控制,限制最高并发是 100。 那么 Entry 的时候携带上的参数列表 ["sentinel", any number],第一个参数出现 "sentinel" 的请求,并发量不超过 100。
type Rule struct {
// ID is the unique id
ID string `json:"id,omitempty"`
// Resource is the resource name
Resource string `json:"resource"`
// MetricType indicates the metric type for checking logic.
// For Concurrency metric, hotspot module will check the each hot parameter's concurrency,
// if concurrency exceeds the Threshold, reject the traffic directly.
// For QPS metric, hotspot module will check the each hot parameter's QPS,
// the ControlBehavior decides the behavior of traffic shaping controller
MetricType MetricType `json:"metricType"`
// ControlBehavior indicates the traffic shaping behaviour.
// ControlBehavior only takes effect when MetricType is QPS
ControlBehavior ControlBehavior `json:"controlBehavior"`
// ParamIndex is the index in context arguments slice.
// if ParamIndex is great than or equals to zero, ParamIndex means the <ParamIndex>-th parameter
// if ParamIndex is the negative, ParamIndex means the reversed <ParamIndex>-th parameter
ParamIndex int `json:"paramIndex"`
// Threshold is the threshold to trigger rejection
Threshold int64 `json:"threshold"`
// MaxQueueingTimeMs only takes effect when MetricType is QPS and ControlBehavior is Throttling
MaxQueueingTimeMs int64 `json:"maxQueueingTimeMs"`
// BurstCount is the silent count
// BurstCount only takes effect when MetricType is QPS and ControlBehavior is Reject
BurstCount int64 `json:"burstCount"`
// DurationInSec is the time interval in statistic
// DurationInSec only takes effect when MetricType is QPS
DurationInSec int64 `json:"durationInSec"`
// ParamsMaxCapacity is the max capacity of cache statistic
ParamsMaxCapacity int64 `json:"paramsMaxCapacity"`
// SpecificItems indicates the special threshold for specific value
SpecificItems map[interface{}]int64 `json:"specificItems"`
}
属性 | 说明 | 是否必填项 | 默认值 |
---|---|---|---|
Resource | 资源名 | 必填 | 无 |
MetricType | 流控指标类型 (MetricType ),支持两种:请求数和并发数 | 必填 | 无 |
ControlBehavior | 流控的效果 (ControlBehavior ),仅在请求数模式下有效。支持两种:快速失败和匀速+排队模式 | 必填 | 无 |
ParamIndex | 热点参数的索引,对应 WithArgs(args ...interface{}) 中的参数索引位置,从 0 开始 | 必填 | 无 |
Threshold | 限流阈值(针对每个热点参数) | 必填 | 无 |
MaxQueueingTimeMs | 最大排队等待时长(仅在匀速排队模式 + QPS 下生效) | 选填 | 无 |
BurstCount | 静默值(仅在快速失败模式 + QPS 下生效) | 选填 | 无 |
DurationInSec | 统计结构填充新的 token 的时间间隔 (仅在请求数(QPS)流控模式下生效) | 选填 | 无 |
ParamsMaxCapacity | 统计结构的容量最大值(Top N) | 选填 | 20000 |
SpecificItems | 特定参数的特殊阈值配置,可以针对指定的参数值单独设置限流阈值,不受前面 Threshold 阈值的限制。 | 选填 | 无 |
热点参数流控策略
热点参数流控的控制策略由 MetricType
和 ControlBehavior
两个字段决定。
MetricType
表示热点参数流控的统计metric类型,Sentinel支持两种:请求数(QPS)和并发数(Concurrency)。
- Concurrency:基于并发数控制热点参数,这种设置下会使用统计结构中当前参数的并发数来执行流控策略。MetricType是Concurrency时候,字段ControlBehavior不会生效,如果当前参数的并发数超过了阈值,那么就拒绝该请求,如果没超过阈值,就通过检查。
- QPS:基于请求数控制热点参数,基于token bucket记录的数据和字段ControlBehavior的策略执行流控。
ControlBehavior
表示热点参数流量控制器的控制行为,Sentinel
支持两种控制行为:Reject
(拒绝)和 Throttling
(匀速排队),需要强调的是,ControlBehavior
仅仅在 MetricType
是 QPS
时候才生效。
- Reject:表示如果当前统计周期(
DurationInSec
)内,统计结构内参数的token已经用完了,就直接拒绝,如果没用完就获取token,通过检查。 - Throttling:表示匀速排队的统计策略。
热点参数流控统计结构
Sentinel
在加载规则时候会将热点参数流控规则转换成热点参数流量控制器,每个流量控制器都有自己独立的统计结构。Sentinel的热点参数流量控制器的独立统计结构是基于token bucket的思想实现的。统计结构缓存了每个埋点参数的三个metric:上次填Token时间、当前统计时间间隔内剩余Token、当前参数的并发数。
流量控制器的统计结构基于LRU的策略,每个规则默认缓存20000个参数的统计数据。
常见场景规则设置
基于并发数控制热点参数:
针对资源,some-test,在参数列表中的第一个参数(index是0)进行流控,每次更新token的周期是1秒,并发数阈值是100。对于Concurrency来说,ControlBehavior,MaxQueueingTimeMs,BurstCount这三个字段都是无效字段,均不用设置。
{
"resource": "some-test",
"metricType": 0,
"paramIndex": 0,
"threshold": 100,
"durationInSec": 1
}
基于请求数控制热点参数
针对资源,some-test,在参数列表中的第二个参数(index是1)进行流控,每次更新token的周期是1秒,统计时间间隔内请求数阈值是100。对于QPS来说,MaxQueueingTimeMs字段是无效字段,不用设置。 这里配置的流控策略是,超过阈值,直接拒绝流量。
{
"resource": "some-test",
"metricType": 1,
"controlBehavior": 0,
"paramIndex": 1,
"threshold": 100,
"burstCount": 5,
"durationInSec": 1
},