Skip to content

热点参数流控

Peihao Yang edited this page Sep 30, 2021 · 1 revision

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。

Sentinel 通过埋点的形式,在每次使用 EntryBuilder 构建 Entry 的时候通过 with_argswith_attachments 方法携带上需要流控的参数。目前仅支持 String 类型的热点字段。

with_args 函数携带的是一个参数列表。Sentinel 的热点参数流控的每个规则会对参数列表中某一位置的参数生效。根据热点参数流控规则中的参数列表 param_index 属性来指定生效参数位置。Sentinel 会为每个规则都创建独立的统计结构,统计结构会缓存对应参数列表的 param_index 的所有值,根据值的统计做流控。类似得,with_attachmentsparam_key 是优先级更高的键值形式的热点参数添加方式。

这里举个例子:假设创建 Entry 的时候携带上的参数的类型列表是:["first_point", "sencond_point"]。现在有一个规则在 param_index0 的位置生效,规则基于并发数去做控制,限制最高并发是 100。 那么携带的第一个参数是 "first_point" 的请求的 Entry,并发量不得超过 100。

热点参数流控规则

并发隔离规则的定义如下:

pub struct Rule {
	pub id: String,
    pub resource: String,
    pub metric_type: MetricType,
    pub control_strategy: ControlStrategy,
    pub param_index: isize,
    pub param_key: String,
    pub threshold: u64,
    pub max_queueing_time_ms: u64,
    pub burst_count: u64,
    pub duration_in_sec: u64,
    pub params_max_capacity: usize,
    pub specific_items: HashMap<ParamKey, u64>,
}

一条流控规则主要由下面的参数组成,我们可以组合这些元素来实现不同的限流效果:

  • id:规则的唯一标识,使用 API 加载规则时,可省略,默认为随机的 uuid;使用标签宏加载规则时,默认为资源名(同时,标签宏仅支持单一规则)。
  • resource:资源名,即规则的作用目标。
  • metric_type:流控指标类型,支持两种:请求数 MetricType::QPS 和并发数 MetricType::Concurrency
  • control_strategy: 表示流量控制器的控制策略,是一个 ControlStrategy 类型的枚举变量。Reject 表示超过阈值直接拒绝,Throttling 表示匀速排队。
  • param_keyparam_index 从构造 Entry 的参数中取热点字段,前者优先级更高,目前仅支持 String 类型热点字段。
  • threshold: 针对某个热点的阈值。
  • max_queueing_time_ms: 匀速排队的最大等待时间,该字段仅在 QPS 指标下,控制策略为 ControlStrategy::Throttling 时生效。
  • burst_count:静默值,该字段仅在 QPS 指标下,快速失败模式(即 ControlStrategy::Direct 时)生效。
  • duration_in_sec:统计结构填充新的 token 的时间间隔,该字段仅在请求数 (QPS) 流控模式下生效。
  • params_max_capacity:统计结构的容量最大值(Top N),默认为 20000。
  • specific_items: 特定参数的特殊阈值配置,可以针对指定的参数值单独设置限流阈值,不受前面 threshold 阈值的限制。

热点参数流控策略

热点参数流控的控制策略由 MetricTypeControlBehavior 两个字段决定。

MetricType 表示热点参数流控的统计指标类型,Sentinel支持两种:请求数 (QPS) 和并发数 (Concurrency)。

  • Concurrency:基于并发数控制热点参数,这种设置下会使用统计结构中当前参数的并发数来执行流控策略。MetricTypeConcurrency 的时候,字段 ControlBehavior 不会生效,如果当前参数的并发数超过了阈值,那么就拒绝该请求,如果没超过阈值,就通过检查。
  • QPS:基于请求数控制热点参数,基于令牌桶记录的数据和字段 ControlBehavior 的策略执行流控。

ControlBehavior 表示热点参数流量控制器的控制行为,Sentinel 支持两种控制行为:Reject (快速失败) 和 Throttling (匀速排队),需要强调的是,ControlBehavior 仅仅在 MetricType 是 QPS 时候才生效。

  • Reject:表示如果当前统计周期 (DurationInSec) 内,统计结构内参数的 token 已经用完了,就直接拒绝,如果没用完就获取token,通过检查。
  • Throttling:表示匀速排队的统计策略。

热点参数流控统计结构

Sentinel 在加载规则时候会将热点参数流控规则转换成热点参数流量控制器,每个流量控制器都有自己独立的统计结构。Sentinel 的热点参数流量控制器的独立统计结构是基于令牌桶的思想实现的。统计结构缓存了每个埋点参数的三个指标:上次填 Token 时间、当前统计时间间隔内剩余 Token、当前参数的并发数。

流量控制器的统计结构基于LRU的策略,每个规则默认缓存 20000 个参数的统计数据。

常见场景规则设置

基于并发数控制热点参数:

{
	resource: "some-test".into(),
	metric_type: MetricType::Concurrency,
	param_index: 0,
	threshold: 100,
	duration_in_sec: 1,
    ..Default::default()
},

上面的配置表示:针对资源,some-test,在参数列表中的第一个参数 (index 是 0) 进行流控,每次更新 token 的周期是 1 秒,并发数阈值是 100。对于 Concurrency 来说,control_strategy, max_queueing_time_ms, burst_count这三个字段都是无效字段,均不用设置。

基于请求数控制热点参数

{
    resource: "some-test".into(),
	metric_type: MetricType::QPS,
	control_strategy: ControlStrategy::Reject,
	param_index: 1,
	threshold: 100,
	burst_count: 5,
	duration_in_sec: 1,
    ..Default::default()
},

上面的配置表示:针对资源,some-test,在参数列表中的第二个参数 (index是1) 进行流控。这里配置的流控策略是,超过阈值,直接拒绝流量。每次更新 token 的周期是1秒,统计时间间隔内请求数阈值是 100。对于快速失败 (Reject) 的控制策略来说,max_queueing_time_ms字段是无效字段,不用设置。