Sentinel 限流原理
一、限流规则
在Sentinel中,限流的直接表现形式是,在执行Entry nodeA =SphU.entry(resourceName)
的时候抛出 FlowException 异常。FlowException 是BlockException 的子类,可以捕捉 BlockException 来自定义被限流之后的处理逻辑。
并且,对于同一个资源或者不同资源可以分别创建多条限流规则,FlowSlot会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。
限流规则主要由下面几个因素组成:
- resource:资源名,即限流规则的作用对象
- count : 限流阈值
- grade : 限流阈值类型(QPS 或并发线程数)
- limitApp : 流控针对的调用来源,若为 default 则不区分调用来源
- strategy : 限流策略(基于调用关系的流量控制)
- controlBehavior : 流量控制效果(直接拒绝、Warm Up、匀速排队)
Sentinel中提供了两个限流纬度:
- 并发线程数
- QPS
也就是说,可以选择根据不同的纬度,根据这些纬度的指标去匹配限流规则,一旦达到阈值,则直接触发流量控制。
默认情况下是根据QPS来限流的,这个属性是通过grade进行设置。
二、并发线程数控制
并发数控制用于保护业务线程池不被慢调用耗尽。当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。
为了应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(Hystrix 线程池隔离)。
这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 (开销)比较大,特别是对低延时的调用有比较大的影响。
Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于Hystrix 信号量隔离。
并发线程数控制参数配置(并发线程数控制通常在调用端进行配置):
- grade: RuleConstant.FLOW_GRADE_THREAD
- count: 此时它的含义是并发线程数量
三、QPS流量控制
当 QPS 超过某个阈值的时候,则采取措施进行流量控制行为(类似于我们前面说过的限流算法上的差异)。
Sentinel提供了四种流量控制行为
- 直接拒绝(CONTROL_BEHAVIOR_DEFAULT)
- Warm Up(CONTROL_BEHAVIOR_WARM_UP)
- 匀速排队(CONTROL_BEHAVIOR_RATE_LIMITER,漏桶算法 )
- 冷启动+匀速器(CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER),除了让流量缓慢增
加,还还控制的了请求的间隔时间,让请求均匀速度通过。
这四个行为,是通过FlowRule中的controlBehavior属性来控制,默认是直接拒绝。
3.1、直接拒绝
是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。
这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
3.2、Warm Up
即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压
垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
属性设置:
controlBehavior: RuleConstant.CONTROL_BEHAVIOR_WARM_UP
warmUpPeriodSec:预热时间,默认60s。
3.3、匀速排队
会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,其实对应的是漏桶算法。当请求数量远远大于阈值时,这些请求会排队等待,这个等待时间可以设置,如果超过等待时间,那这个请求会被拒绝。这种方式主要用于处理间隔性突发的流量,例如消息队列。
属性设置:
controlBehavior:RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
maxQueueingTimeMs:排队等待时间,表示每一次请求最长等待时间,默认是500ms
四、基于调用关系的流量控制
在分布式架构中,一个请求会包含调用方和被调用方,Sentinel还提供了服务调用关系的流量控制策略,所谓的调用关系,就是根据不同的调用纬度来触发流量控制。
- 根据调用方限流(STRATEGY_DIRECT)
- 根据调用链路入口限流(STRATEGY_CHAIN)
- 具有关系的资源流量控制(STRATEGY_RELATE)
4.1、根据调用方限流
比如有两个服务分别是A和B,都向某一个服务C发起请求调用,这个时候我们希望对来自服务B的请求进行限流,那就可以采用调用方限流策略,
属性设置:
strategy:STRATEGY_DIRECT
LimitApp:
- default,表示不区分调用者。
- ${some_origin_name},针对特定的调用者。
- other,表示针对除了${some_origin_name}以外的其他调用方的流量进行流量控制。
4.2、根据调用链路入口限流
一个被限流的保护方法,可能来自于不同的调用链路,比如针对资源NodeA,入口Entrance1 和 Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。
属性设置:
strategy:STRATEGY_CHAIN
refResource:Entrance1,表示只有从入口Entrance1的调用才会进行流量控制
4.3、具有关系的资源流量控制
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。
属性设置:
strategy:=STRATEGY_RELATE
refResource:write_db,表示设置关联资源
通过这样的设置后,如果write_db资源超过阈值时,就会对read_db资源进行限流。
总结:
Sentinel 限流 ,本质上都是当前系统所关注的资源保护指标,最终意义是保护系统,让系统平稳运行!