1 修改历史
2 概述
2.1 术语
2.2 背景
随着用户量越来越大,服务偶尔会出现满负荷运行,极端情况下服务OOM或者假死需要很久才能恢复正常,如果重启可能会瞬间CPU飙升,使响应时间增长,影响用户体验,应该尽量避免,所以引入限流拒绝请求来降低服务器峰值后的压力。
2.3 目标
车辆、订单、客户、权限、元数据、通用中台都需要接入限流,避免服务器峰值后压力持续增加,导致服务不可用。
2.4 接入方式
sentinel官网:https://sentinelguard.io/zh-cn/index.html
4 原理剖析
4.1 总体架构
4.2 定义资源
支持手动定义资源、异步以及注解定义
// 手动定义,来源于官网 Entry entry = null; // 务必保证 finally 会被执行 try { // 资源名可使用任意有业务语义的字符串,注意数目不能太多(超过 1K),超出几千请作为参数传入而不要直接作为资源名 // EntryType 代表流量类型(inbound/outbound),其中系统规则只对 IN 类型的埋点生效 entry = SphU.entry("自定义资源名"); // 被保护的业务逻辑 // do something... } catch (BlockException ex) { // 资源访问阻止,被限流或被降级 // 进行相应的处理操作 } catch (Exception ex) { // 若需要配置降级规则,需要通过这种方式记录业务异常 Tracer.traceEntry(ex, entry); } finally { // 务必保证 exit,务必保证每个 entry 与 exit 配对 if (entry != null) { entry.exit(); } }
dubbo adapter中使用
//com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter //统计接口 interfaceEntry = SphU.entry(interfaceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN); //统计方法 methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments());
4.3 定义规则
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。参考:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
4.3.1 流量控制(FlowControl)
Field |
说明 |
默认值 |
resource |
资源名,资源名是限流规则的作用对象 |
|
count |
限流阈值 |
|
grade |
限流阈值类型,QPS 模式(1)或并发线程数模式(0) |
QPS 模式 |
limitApp |
流控针对的调用来源 |
default,代表不区分调用来源 |
strategy |
调用关系限流策略:直接、链路、关联 |
根据资源本身(直接) |
controlBehavior |
流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流 |
直接拒绝 |
clusterMode |
是否集群限流 |
否 |
4.3.1.1 限流策略
- STRATEGY_DIRECT:根据调用方进行限流,根据调用方进行限流。ContextUtil.enter(resourceName, origin) 方法中的 origin 参数标明了调用方的身份。
- STRATEGY_RELATE:根据关联流量限流。当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联,可使用关联限流来避免具有关联关系的资源之间过度的争抢。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。
- STRATEGY_CHAIN:根据调用链路入口限流。假设来自入口 Entrance1 和 Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许根据某个入口的统计信息对资源进行限流。
4.3.1.2 流控效果(FlowRule)
- 直接拒绝:方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。
- Warm Up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
- 匀速排队:会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。主要用于处理间隔性突发的流量,例如消息队列。
4.3.2 熔断降级规则(DegradeRule)
一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
Field |
说明 |
默认值 |
resource |
资源名,即规则的作用对象 |
|
grade |
熔断策略,支持慢调用比例/异常比例/异常数策略 |
慢调用比例 |
count |
慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 |
|
timeWindow |
熔断时长,单位为 s |
|
minRequestAmount |
熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) |
5 |
statIntervalMs |
统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) |
1000 ms |
slowRatioThreshold |
慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
4.3.2.1 熔断策略
- 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
- 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0],代表 0% - 100%。
- 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
4.3.3 系统保护规则(SystemRule)
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
Field |
说明 |
默认值 |
highestSystemLoad |
load1 触发值,用于触发自适应控制阶段 |
-1 (不生效) |
avgRt |
所有入口流量的平均响应时间 |
-1 (不生效) |
maxThread |
入口流量的最大并发数 |
-1 (不生效) |
qps |
所有入口资源的 QPS |
-1 (不生效) |
highestCpuUsage |
当前系统的 CPU 使用率(0.0-1.0) |
-1 (不生效) |
自适应:应该根据系统能够处理的请求,和允许进来的请求,来做平衡,而不是根据一个间接的指标(系统 load)来做限流。最终我们追求的目标是在系统不被拖垮的情况下,提高系统的吞吐率,而不是 load 一定要到低于某个阈值。Sentinel 在系统自适应保护的做法是,用 load1 作为启动自适应保护的因子,而允许通过的流量由处理请求的能力,即请求的响应时间以及当前系统正在处理的请求速率来决定。TCP BBR
4.3.4 来源访问控制规则(AuthorityRule)
根据调用方来限制资源是否通过
4.3.5 热点参数规则(ParamFlowRule)
热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。
4.3.5.1 热点参数规则(ParamFlowRule)
属性 |
说明 |
默认值 |
resource |
资源名,必填 |
|
count |
限流阈值,必填 |
|
grade |
限流模式 |
QPS 模式 |
durationInSec |
统计窗口时间长度(单位为秒),1.6.0 版本开始支持 |
1s |
controlBehavior |
流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 |
快速失败 |
maxQueueingTimeMs |
最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 |
0ms |
paramIdx |
热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置 |
|
paramFlowItemList |
参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。 仅支持基本类型和字符串类型 |
|
clusterMode |
是否是集群参数流控规则 |
false |
clusterConfig |
集群流控相关配置 |
4.4 检验规则是否生效
4.4.1 判断限流降级异常
在 Sentinel 中所有流控降级相关的异常都是异常类BlockException的子类
- 流控异常:FlowException
- 熔断降级异常:DegradeException
- 系统保护异常:SystemBlockException
- 热点参数限流异常:ParamFlowException
4.4.2 block事件
可以通过StatisticSlotCallbackRegistry向StatisticSlot注册回调函数
public interface ProcessorSlotEntryCallback<T> { void onPass(Context context, ResourceWrapper resourceWrapper, T param, int count, Object... args) throws Exception; void onBlocked(BlockException ex, Context context, ResourceWrapper resourceWrapper, T param, int count, Object... args); }
5 对现有系统影响
接入新的基础服务需要分析对现有系统有哪些影响,以及接入方式是否简单。
5.1 性能影响
- 限流使用单机模式,限流规则都会保存在内存中,使用推模式获取修改规则,只有规则变更时才会触发修改,对系统影响很小。集群模式需要远程获取token,影响稍大。
- 限流规则是否生效,仅仅影响计数,对CPU影响很小
- Dashboard通过定时任务10s获取一次客户端的统计数据,客户端需要5s发送一次心跳包保证客户端服务正常
5.2 HTTP接口影响
注意点:
- 由于http限流是针对Servlet filter进行统计限流,Servlet异常处理需要重定向异常页面。
- SpringBoot需要通过FilterRegistrationBean来进行过滤器设置,可能需要改造以前的filter设置。
- 具体处理参考com.alibaba.csp.sentinel.adapter.servlet.CommonFilter#doFilter
5.3 Dubbo接口影响
注意点:
- Dubbo限流也是通过Dubbo consumer及provider端进行统计限流,通过继承DefaultDubboFallback重写异常回调方法来处理异常。
- 具体处理参考:com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter#invoke
6 同类组件功能对比
Sentinel |
Hystrix |
resilience4j |
|
隔离策略 |
信号量隔离(并发控制) |
线程池隔离/信号量隔离 |
信号量隔离 |
熔断降级策略 |
基于慢调用比例、异常比例、异常数 |
基于异常比例 |
基于异常比例、响应时间 |
实时统计实现 |
滑动窗口(LeapArray) |
滑动窗口(基于 RxJava) |
Ring Bit Buffer |
动态规则配置 |
支持近十种动态数据源 |
支持多种数据源 |
有限支持 |
扩展性 |
多个扩展点 |
插件的形式 |
接口的形式 |
基于注解的支持 |
支持 |
支持 |
支持 |
单机限流 |
基于 QPS,支持基于调用关系的限流 |
有限的支持 |
Rate Limiter |
集群流控 |
支持 |
不支持 |
不支持 |
流量整形 |
支持预热模式与匀速排队控制效果 |
不支持 |
简单的 Rate Limiter 模式 |
系统自适应保护 |
支持 |
不支持 |
不支持 |
热点识别/防护 |
支持 |
不支持 |
不支持 |
多语言支持 |
Java/Go/C++ |
Java |
Java |
Service Mesh 支持 |
支持 Envoy/Istio |
不支持 |
不支持 |
控制台 |
提供开箱即用的控制台,可配置规则、实时监控、机器发现等 |
简单的监控查看 |
不提供控制台,可对接其它监控系统 |
7 有哪些可以借鉴的编程思想
- 使用责任链模式DefaultProcessorSlotChain,不同Slot不同处理逻辑
- 提供很好的框架支持,dubbo、grpc、servlet、zuul、okhttp等
- 提供很好的扩展接口,用于业务处理自己的逻辑,比如DubboFallback、CommonFilter
- StatisticNode中LongAdder线程数统计、滑动窗口MetricBucket中LongAdder使用(写多读少)