流控,即流量控制(Flow Control),根据流量、并发线程数、响应时间等指标,把随机到来的流量调整成合适的形状,即流量塑形。避免应用被瞬时的流量高峰冲垮,从而保障应用的高可用性。

流量控制有以下几个角度:

  • 运行指标,例如 QPS、并发线程数等。
  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系,调用来源等。
  • 控制效果,例如直接拒绝、Warm Up(预热)、排队等待等。

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

  • 资源名:即流控规则的作用对象
  • 阈值:流控阈值
  • 阈值类型:流控阈值类型(QPS 或并发线程数)
  • 来源应用:流控规则针对的调用来源,若为 default 则不区分调用来源
  • 流控方式:调用关系限流策略
  • 流控模式:即流控效果,包括快速失败、Warm Up、排队等待模式

运行指标

流量控制支持通过以下运行指标进行流量塑形:

  • 基于 QPS

    QPS 模式根据资源的实时 QPS 进行流量控制。当 QPS 超过指定阈值时采取相应的控制策略(参见后面的 控制效果章节)。

  • 基于线程数

    线程数模式按照资源的并发线程数(即该资源正在执行的线程数)进行流量控制。

    并发线程数限流用于保护业务线程数不被耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目,如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。

资源的调用关系

调用关系包括调用方和被调用方。一个函数可能会去调用另一个函数,形成一个调用链路的层次关系。Sentinel 会记录调用链路的实时统计信息,因此可以衍生出多种按调用关系进行流量控制的手段。

流控模式支持以下几种资源的调用关系:直接模式(按调用方限流)、关联模式(关联资源限流)和链路模式(调用链路限流)。

  • 根据调用来源限流

    直接模式下会针对流控规则中的来源应用进行流量控制。

    流控规则中的 limitApp 字段用于根据调用方进行流量控制。该字段的值有以下三种选项,分别对应不同的场景:

    • default:表示不区分调用来源,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。
    • {some_origin_name}:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如 NodeA配置了一条针对调用者 caller1 的规则,那么当且仅当来自 caller1NodeA 的请求才会触发流量控制。
    • other:表示针对除 {some_origin_name} 以外的其余调用方的流量进行流量控制。例如,资源NodeA配置了一条针对调用者 caller1 的限流规则,同时又配置了一条调用者为 other 的规则,那么任意来自非 caller1NodeA 的调用,都不能超过 other 这条规则定义的阈值。

      直接模式下直接控制来自调用来源的访问流量;如果来源应用为 default 则不区分调用来源。

  • 关联限流

    关联模式会控制当前资源的关联资源的流量。

    当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 关联资源write_db。这样当写库操作过于频繁时,读数据的请求会被限流。

  • 链路限流

    链路模式下会控制该资源所在的调用链路入口的流量。需要在规则中配置入口资源,即该调用链路入口的上下文名称。

    一棵典型的调用树如下图所示:

    machine-root
                        /       \
                       /         \
                 Entrance1     Entrance2
                    /             \
                   /               \
          DefaultNode(nodeA)   DefaultNode(nodeA)

上图中来自入口 Entrance1Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个调用入口的统计信息对资源限流。比如链路模式下设置入口资源为 Entrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。

调用链的入口(上下文)是通过 API 方法 ContextUtil.enter(contextName) 定义的,其中 contextName 即对应调用链路入口名称。

控制效果

流控方式(控制效果)指的是,当阈值类型为 QPS 时,选择如何控制流量,处理被拦截的流量,实现流量塑形。流量控制的手段包括以下几种:快速失败、Warm Up、排队等待。

说明 控制效果仅对 QPS 限流生效。
  • 快速失败

    快速失败方式是默认的流量控制方式,当 QPS 超过规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

  • Warm Up

    当系统长期处于空闲的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过 Warm Up 模式(预热模式),让通过的流量缓慢增加,经过设置的预热时间以后,到达系统处理请求速率的设定值。

    Warm Up 模式默认会从设置的 QPS 阈值的 1/3 开始慢慢往上增加至 QPS 设置值。

  • 排队等待

    排队等待模式下会严格控制请求通过的间隔时间,即请求会匀速通过,允许部分请求排队等待,通常用于消息队列削峰填谷等场景。需设置具体的超时时间,当计算的等待时间超过超时时间时请求就会被拒绝。

    例如,QPS 配置为 5,则代表请求每 200 ms 才能通过一个,多出的请求将排队等待通过。超时时间代表最大排队时间,超出最大排队时间的请求将会直接被拒绝。排队等待模式下,QPS 设置值不要超过 1000(请求间隔 1 ms)。