文章目录
之前学习了Sentinel的使用,这里还要看一下Sentinel控制台各个菜单的用处
Sentinel规则配置详解
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能
。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
阿里云提供了 企业级的 Sentinel 控制台,应用高可用服务 AHAS
实时监控菜单
监控接口的通过的QPS和拒绝的QPS
。同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。
注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。
注意:请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致,否则会导致拉不到实时的监控数据。
簇点链路菜单
用来显示微服务的所监控的API。
簇点链路(单机调用链路)页面实时的去拉取指定客户端资源的运行情况。它一共提供两种展示模式:一种用树状结构展示资源的调用链路,另外一种则不区分调用链路展示资源的运行情况。
注意: 簇点监控是内存态的信息,它仅展示启动后调用过的资源。
换句话说,如果某个API一直没被调用过,那么就不会出现在这个菜单下
流控规则
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制
,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 参考官方文档
同一个资源可以创建多条限流规则。
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果
字段 | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS 模式(1)或并发线程数模式(0) | QPS 模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流 | 直接拒绝 |
clusterMode | 是否集群限流 | 否 |
表格中的字段都是java代码中FlowRule
类对应的字段,有感兴趣的可以看一下这个类
限流阈值类型
流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS
。类型由 FlowRule 的 grade 字段来定义。其中,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。
QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
流控模式
直接
资源调用达到设置的阈值后直接被流控抛出异常
关联
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。
如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢
这里说一下: 是给关联资源B配置个规则和阈值,当达到了阈值后,被流控是资源A而不是B,举例说明:有一张表,分别有两个接口,读写分离,但当写的频率过高时,就降低读的频率或者直接不让读了,此时写的接口就是资源B,读的操作就是资源A
链路
根据调用链路入口限流。
举例说明:比如此时在一个Service方法上加了限流规则,但入口有两个API都会调用这个Service方法,当达到规则阈值时,就可以使某一个API限流,对另一个入口API不做控制
比如高铁站上高铁的入口只有一个,但安检队伍有2个,当上高铁的入口流量过大时,我就停止一个安检队伍的安检,但另一个安检队伍不受影响,可以继续安检并进入入口。
注意使用链路模式时,需要在yml中配置一个参数,否则不生效
# 将其配置为 false 即可根据不同的 URL 进行链路限流
spring.cloud.sentinel.web-context-unify: false
流控效果
当 QPS 超过某个阈值的时候,则采取措施进行流量控制
。流量控制的效果包括以下几种:快速失败(直接拒绝)、Warm Up(预热)、匀速排队(排队等待)
。
- 快速失败:达到阈值后,
新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式
。 - warm up:预热模式,
对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化
,从一个较小值逐渐增加到最大阈值。 - 排队等待:
让所有的请求按照先后次序排队执行
,两个请求的间隔不能小于指定时长
快速失败
(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
Warm Up(用的比较多)
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
下面操作说明一下:QPS阈值设置为3(我这里没有下载模拟线程工具,QPS设置稍微有点小了,凑合着看吧),预热时长为5秒
通过接口访问,实时监控页面可以看到,刚开始的阈值是3/3=1,大于1的请求直接失败了,后面在5秒内逐渐把阈值升到3
匀速排队
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过
,对应的相似的是漏桶算法。
设置QPS阈值为3,排队等待时间为3000(单位毫秒)
,同一秒超过3的访问会放到队列中,放到下一秒执行,但不会一直在队列中等待,如果等待时间超过了超时时间,就不执行了
熔断降级规则
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。
我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置
。
熔断降级规则说明
熔断降级规则(DegradeRule)包含下面几个重要的属性:
字段 | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
count | 限流阈值 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 (1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms)(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
慢调用策略
在统计时长窗口1秒内有至少5个请求,且 5*比例阈值0.5 = 2.5个请求的响应时间超过200毫秒,那么就把此接口熔断2秒,在这2秒内所有请求都失败。等2秒过后,在尝试一个请求是否相应<200毫秒,若是<200毫秒,那么接口可以正常请求(熔断器打开),重复上面统计;若>200毫秒,接口继续熔断等待下一次尝试。
异常比例策略
在统计时长窗口
1秒内有至少N个请求
(这里是5个),且 有N*比例阈值0.4个请求的发生了异常
(这里是5*0.4=2),那么就把此接口熔断M秒
(这里是2秒),在这M秒内所有请求都失败(如果请求数达不到最小请求数,即使请求全发生异常也不会熔断)
。等M秒过后,在尝试一个请求是否不会发生异常,若没有异常,那么接口可以正常请求(熔断器打开),重复上面统计;若接口还是异常,接口继续熔断等待下一次尝试
异常数策略
和异常比例策略相比,就是把比例值换成具体的异常数,其他没区别
热点规则
热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
注意:
1.热点规则需要使用@SentinelResource("resourceName")注解,否则不生效
2.参数必须是7种基本数据类型才会生效
上面截图的意思:配置一个资源名叫userinfo的热点规则,参数类型是int,如果参数值=1,那么限流阈值就是3;如果参数值不是1,那么限流阈值就是1
@RequestMapping("/info/{id}")
// 这里必须用注解@SentinelResource,拦截器中的流控代码对热点规则无效
@SentinelResource(value = "userinfo", blockHandler = "handleException")
public R info(@PathVariable("id") Integer id){
UserEntity user = userService.getById(id);
return R.ok().put("user", user);
}
系统规则——系统自适应保护
Sentinel 做系统自适应保护的目的:
- 保证系统不被拖垮
- 在系统稳定的前提下,保持系统的吞吐量
系统保护规则是从应用级别的入口流量进行控制
,从单台机器的总体 Load、RT、入口 QPS 和线程数四个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效
。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则阈值类型
- Load
(负载)
(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。 - CPU usage(1.5.0+ 版本):当系统
CPU 使用率
超过阈值即触发系统保护(取值范围 0.0-1.0)。 - RT(响应时间):当单台机器上
所有入口流量的平均 RT
达到阈值即触发系统保护,单位是毫秒。 - 线程数:当单台机器上
所有入口流量的并发线程数
达到阈值即触发系统保护。 - 入口 QPS:当单台机器上
所有入口流量的 QPS
达到阈值即触发系统保护。
授权控制规则——来源访问控制(黑白名单)
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过
。
来源访问控制规则(AuthorityRule)非常简单,主要有以下配置项:
- resource:资源名,即限流规则的作用对象。
- limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB。
- strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。
授权规则还需要改代码,实现com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser接口,在parseOrigin方法中区分来源,并将此类交给spring管理
@Component
public class MyRequestOriginParser implements RequestOriginParser {
/**
* 通过request获取来源标识,交给授权规则进行匹配
* @param request
* @return
*/
@Override
public String parseOrigin(HttpServletRequest request) {
// 标识字段名称可以自定义
String origin = request.getParameter("serviceName");
// if (StringUtil.isBlank(origin)){
// throw new IllegalArgumentException("serviceName参数未指定");
// }
return origin;
}
}
第二步:配置授权规则(给/test3接口配置白名单,是user和order的可以访问接口)
测试:
-
serviceName=user || serviceName=order放行
-
serviceName!=user && serviceName !=order 不放行
其实感觉就是你在外面配置一个黑/白名单的String数组,然后代码中获取一个参数值(参数名随便写,最终返回这个参数值 request.getParameter("随便写"),最终return就好); 然后Sentinel会拿到这个返回值,去跟黑/白名单中的数据对比,再决定是放行还是拦截
,这只是个人理解,后续看源码后再回来补充这里
集群规则
为什么要使用集群流控呢?假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判断是否可以调用。这就是最基础的集群流控的方式。
集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果
。
集群流控官方文档页面,但是我使用的1.8.6貌似有一些bug,凑合着看看怎么使用的就行了
集群流控中共有两种身份:
- Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。
- Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。
Sentinel 集群流控支持限流规则和热点规则两种规则,并支持两种形式的阈值计算方式:
- 集群总体模式:即限制整个集群内的某个资源的总体 qps 不超过此阈值。
- 单机均摊模式:单机均摊模式下配置的阈值等同于单机能够承受的限额,token server 会根据连接数来计算总的阈值(比如独立模式下有 3 个 client 连接到了 token server,然后配的单机均摊阈值为 10,则计算出的集群总量就为 30),按照计算出的总的阈值来进行限制。这种方式根据当前的连接数实时计算总的阈值,对于机器经常进行变更的环境非常适合。
启动方式
Sentinel 集群限流服务端有两种启动方式:
-
独立模式(Alone),即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作(需要额外部署一个其他服务)。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。
-
嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。(直接把集群中某个节点作为 Token Server)
集群限流使用
- 指定Token Server的集群和Token Client的机器
- 指定接口限流
指定集群模式、阈值、TokenServer失败是否退化为单机限流(防止TokenServer机器挂了,毕竟没有高可用)
然后就访问接口测试了,但1.8.6版本貌似有bug,这里知道怎么用就行了
Sentinel工作原理
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:
- NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
- ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
- StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
FlowSlot
则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;- AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
DegradeSlot
则通过统计信息以及预设的规则,来做熔断降级;SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量;
总体的框架如下:
Sentinel 将 ProcessorSlot 作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder 作为 SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。