📝 学技术、更要掌握学习的方法,一起学习,让进步发生
👩🏻 作者:一只IT攻城狮 ,关注我,不迷路 。
💐学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。
💐学习建议:2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。
❤️ 《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。
文章目录
- 一、Sentinel流量控制(flow control)
- 1、流量控制参数说明
- 2、自定义异常信息
- 3、流控效果-快速失败
- 4、流控效果-Warm Up
- 5、流控效果-排队等待
- 6、阈值类型-并发线程数控制
- 二、Sentinel熔断降级
- 1、熔断策略-慢调用比例
- 2、熔断策略-异常比例
- 3、熔断策略-异常数
- 三、Sentinel热点参数限流
- 四、系统规则
- 五、授权控制规则
- 六、 集群规则
一、Sentinel流量控制(flow control)
📢:关于Sentinel基本概述和控制台的集成参看:SpringCloud入门实战(十四)Sentinel微服务流量防卫兵简介
❤️:本篇文章重点探讨一下Sentinel关键特性:流量控制与熔断降级的原理和Sentinel控制台的配置。
1、流量控制参数说明
其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
说明:
规则 | 说明 |
---|---|
资源名: | 唯一名称,默认请求路径 |
针对来源: | Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源)。 |
阈值类型/单机阈值: | a: QPS(每秒钟的请求数量),当调用该api的QPS达到阈值的时候,进行限流。 b: 线程数:每调用该API的线程数达到阈值的时候,进行限流,用于保护业务线程池不被慢调用耗尽。 |
是否集群: | |
流控模式: | a: 直接:API达到限流条件时,直接限流。 b: 关联:当关联的资源达到阈值时,就限流自己。 c: 链路:只记录链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对来源】 |
流控效果: | a:快速失败:直接失败,抛异常【默认的流控处理】 b:Warm Up: 即预热/冷启动方式。根据codeFactor (冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。 c:排队等待:均匀排队,让请求以均速的速度通过,阈值类型必须设置为QPS,否则无效。 |
同一个资源可以创建多条限流规则。FlowSlot会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。一条限流规则主要由上面几个因素组成,我们可以组合这些元素来实现不同的限流效果。
基于调用关系的流量控制。调用关系包括调用方、被调用方;一个方法可能会调用其它方法,形成一个调用链路的层次关系。
Sentinel 底层采用高性能的
滑动窗口
数据结构 LeapArray 来统计实时的秒级指标数据,可以很好地支撑写多于读的高并发场景。滑动窗口算法
也是Sentinel的默认算法。
2、自定义异常信息
在前面的例子中,无论是熔断降级还是被限流返回的异常信息都是Blocked by Sentinel (flow limiting)
,这个是Sentinel默认的异常信息。很显然默认的异常信息并不能满足我们的业务需求,因此我们需要根据前后端规则制定自己的异常返回信息。
这里将会用到一个注解@SentinelResource
,这个在上文也是提到过,这个注解中有两个关于限流兜底方法的属性,如下:
- blockHandler: 对应处理 BlockException 的函数名称。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。
- blockHandlerClass:兜底方法必须要和业务方法放在同一个类中,这样代码耦合度不是很高吗?@SentinelResource提供一个属性blockHandlerClass,完美的解决了这一个问题,能够将兜底方法单独放在一个类中指定。blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
3、流控效果-快速失败
代码改造:在@SentinelResource注解中指定blockHandler处理BlockException
public class TestController {@GetMapping("/testA")@SentinelResource(value = "testA",blockHandlerClass = TestController.class,blockHandler = "testBlock")public CommonResult<String> testA() {return new CommonResult<>(200, "success", "testA");}public static CommonResult<String> testBlock(BlockException e){CommonResult result=new CommonResult();result.setCode(5000);result.setMessage("Sentinel流量控制!");return result;}@GetMapping("/testB")public CommonResult<String> testB() {return new CommonResult<>(200, "success", "testB");}
}
注意📢:value将该方法定义为sentinel的资源,blockHandlerClass指明流控处理的类,blockHandler是流控时调用的方法。
接下来进行简单测试:我们上面配置了阈值为2,然后连续访问2次接口测试,报错,达到限流效果。
4、流控效果-Warm Up
Warm Up(RuleConstant Control_behavior_warm_up)方式,即预热/冷启动方式。
公式:阈值除以coldFactor(冷加载因子默认值为3),经过预热时间后才能达到阈值。
举例:如上配置的意思是,阈值为10+预热时长设置为5秒,QPS会从3慢慢过渡到10。
系统初始化的阈值为10/3约等于3,即阈值刚开始为3,然后过了5秒后阈值才慢慢升高恢复到10。
比如,商城的秒杀等系统服务,过一段时间后增加阈值。
5、流控效果-排队等待
匀速排队(Ruleconstant.CONTROL BEHAVIOR RATE LINITER ) 方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法
。让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐步处理请求,而不是在第一秒直接拒绝多余的请求。
举例:如上配置的意思是,testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。
注意📢:匀速排队模式暂时不支持 QPS > 1000 的场景
6、阈值类型-并发线程数控制
并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。
Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。
注意📢:sentinel和nacos一样不配置持久化的话,默认是存储在内存中,重启配置失效。
二、Sentinel熔断降级
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超市或异常比例升高),对这个资源的调用进行限制,请请求快速失败,避免影响到其它的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
说明:
规则 | 说明 |
---|---|
资源名: | 唯一名称,默认请求路径 |
熔断策略: | a.(默认值)慢调用比例 b.异常比例(秒级) c. 异常数(分钟级) |
RT | RT:平均响应时间,秒级。 RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max=xxxx才能生效) |
熔断时长: | 窗口期过后关闭断路器 |
慢调用比例阈值: | 慢调用比例阀值,仅慢调用比例模式有效 (1.8.0 引入) 比率的阈值范围是 [0.0, 1.0] ,代表 0% - 100%。 |
最小请求数: | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出闻值也不会熔断 (1.7.0 引入) 默认值 5 |
统计时长: | 统计计时长(单位为 ms),如 60*1000 代表分钟级 (1.8.0 引入) 默认值 1000ms |
Sentinel的断路器时没有半开状态的。半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix。
1、熔断策略-慢调用比例
慢调用比例(SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
举例:如上配置的意思是,当前允许的最大响应时间是100ms,大于当前值就是慢调用,单位时间内请求数目大于5,并且慢调用比例大于0.2,在接下来的3s内会自动熔断。
2、熔断策略-异常比例
异常比例(ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0]
,代表 0% - 100%。
举例:如上配置的意思是,1s内请求数大于5,并且异常比例大于0.4,接下来熔断时长内请求就会自动熔断。
3、熔断策略-异常数
异常数(ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
举例:如上配置的意思是,当单位统计时长1s内的异常数目超过值2之后会自动进行熔断。
注意📢:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。
三、Sentinel热点参数限流
注意📢:热点参数限流只针对QPS。
顾名思义:热点
就是经常访问的数据,很多时候肯定是希望统计某个访问频次Top K数据并对其进行限流。
比如秒杀系统中的商品ID,对于热点商品那一瞬间的并发量是非常可怕的,因此必须要对其进行限流。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法
来进行参数级别的流控。
热点参数限流
会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
配置参数说明:
注意📢:热点规则需要使用@SentinelResource(“resourceName”)注解,否则不生效。
参数必须是7种基本数据类型才会生效。
输入http://localhost:8401/hotKey?p1=“1”&p2=“2” 测试:
上述配置的具体含义:当hotKey这个资源中的第0个参数QPS超过1秒2次将会被限流。
从上图配置中,我们将参数值p1这个参数值等于100的时候,限流阈值设置成了100,也就是说p1=100这个请求QPS放宽到1秒请求100次以上才会被限流。
四、系统规则
前面热点参数、普通流量限流都是针对的某个接口,这里系统自适应限流针对是整个系统的入口流量,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
阈值类型有五种,分别如下:
阈值类型 | 说明 |
---|---|
Load 自适应(仅对 Linux/Unix-like 机器生效): | 系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是CPU cores * 2.5 |
平均 RT: | 当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。 |
并发线程数: | 当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。 |
入口 QPS: | 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。 |
CPU usage(1.5.0+ 版本): | 当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。 |
注意:系统规则中的入口QPS这个规则不建议配置,一旦配置上了该微服务中的所有接口都将会被这个规则限制,可能导致整个服务不可用。
五、授权控制规则
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
来源访问控制规则(AuthorityRule)非常简单,主要有以下配置项:
阈值类型 | 说明 |
---|---|
resource: | 资源名,即限流规则的作用对象。 |
limitApp: | 对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB。 |
strategy: | 限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。 |
六、 集群规则
为什么要使用集群流控呢?假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判断是否可以调用。这就是最基础的集群流控的方式。
另外集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。
集群流控中共有两种身份:
- Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。
- Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。
Sentinel 集群流控支持限流规则和热点规则两种规则,并支持两种形式的阈值计算方式:
- 集群总体模式:即限制整个集群内的某个资源的总体 qps 不超过此阈值。
- 单机均摊模式:单机均摊模式下配置的阈值等同于单机能够承受的限额,token server 会根据连接数来计算总的阈值(比如独立模式下有 3 个 client 连接到了 token server,然后配的单机均摊阈值为 10,则计算出的集群总量就为 30)
好了,Sentinel控制台配置就介绍到这里了。