Spring Cloud 系列笔记
Sentinel简介
核心代码
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
核心配置
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
- 启动项目后需要访问某个接口(懒加载)才能在sentinel界面看到监控数据
流控规则解析
- 资源名:唯一,默认请求路径(如:http://localhost:port/testA)
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制)
- 阈值类型/单机阈值:
- 1、QPS(每秒钟的请求数量):当调用该接口的QPS达到了阈值的时候,进行限流;
- 2、线程数:当调用该接口的线程数达到阈值时,进行限流
- 线程数代表的是每秒内访问api接口的线程数,如果该接口的操作比较长,当排队的线程数到达阈值的时候,进行限流操作,相反的如果接口的操作很快,即是没秒内的操作很快,同样不会进行限流操作。QPS可以简单的理解为访问次数,但是线程数是和
接口处理的快慢 有关的。 - 是否集群:不需要集群
- 流控模式:
- 1、直接:接口达到限流条件时,直接限流
- 2、关联:当关联的资源达到阈值时,就限流自己(应用场景:
支付接口达到阈值,就限流下订单的接口 ) - 3、链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以限流)[api级别的针对来源]
- 流控效果
- 1、快速失败:直接失败
- 2、Warm Up:即请求 QPS 从
最大阈值 / 3 (codeFactor,冷加载因子,默认为3)开始,经预热时长逐渐升至设定的阈值(应用场景:秒杀的瞬间,可能把系统打死,采用预热可以慢慢放流量进来,阈值不是一开始就最大 ) - 3、排队等待(类似于漏桶算法)(应用场景:处理间隔性突发流量,例如消息队列)
熔断降级
慢调用比例RT (SLOW_REQUEST_RATIO)
- 设置允许的 慢调用 RT(即
最大的响应时间 ),请求的响应时间大于该值则统计为慢调用。 - 当
统计时长 内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 - 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于则会再次被熔断。
异常比例 (ERROR_RATIO)
- 这里的异常是指接口业务代码抛的异常
- 当统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
- 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (ERROR_COUNT)
- 当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
热点key的流控
- 热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
测试代码
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String hotKeyTest(@RequestParam(value = "p1", required = false)String p1,
@RequestParam(value = "p2", required = false)String p2){
return "===== (*^_^*) 成功了 (*^_^*) =====";
}
public String deal_testHotKey(String p1, String p2, BlockException exception){
return "===== (ㄒoㄒ) 失败了 (ㄒoㄒ) =====";
}
配置热点参数的阈值
- 发出请求并带上 p1 参数,访问 :http://localhost:8401/testHotKey?p1=aaa
- 如果 1 秒点一下,可以正常访问,但是 1 秒内,连续请求,就会走备选方案
- 注意资源名也可以是url地址哦
参数例外项
- 上述情况,不论被监控的参数传入的是何值,都会进行判断,并限流
- 但是有些时候有些特殊值,希望它的阈值和其他不一样,就要使用该配置
- 比如说:p1 传入 aaa 时的阈值可以允许达到 100,但是其他值只能达到 10
系统保护规则(整体维度)
- 简单来说,就是从整体维度对入口进行流控
- 名词解释:
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
- CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
@SentinelResource使用
- 该注解用于配合sentinel控制台进行流控、熔断降级等操作,通过它可以指定自定义的降级策略,而不是阿里的直接返回一个blockException
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id)
{
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
if (id == 4) {
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
}else if (result.getData() == null) {
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
value属性
BlockHandler属性
- 处理BlockException的函数,该函数只负责sentinel控制台配置的违规
- 注意:
- 必须是 public
- 返回类型与原方法一致
- 参数类型需要和原方法相匹配,并在最后加 BlockException 类型的参数。
- 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法。
blockHandlerClass属性
exceptionsToIgnore属性
fallback属性
- fallback 函数名称
- 可选项,用于在接口抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
- fallback 函数签名和位置要求
- 返回值类型必须与原函数返回值类型一致
- 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常
- fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析
自定义降级处理类(可以代码解耦)
public class CustomerBlockHandler
{
public static CommonResult handlerException(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----1");
}
public static CommonResult handlerException2(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----2");
}
}
Controller配置
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
整合OpenFeign
- 这里采用的是一个消费者,两个服务提供者,消费者服务需要引入Feign的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
feign:
sentinel:
enabled: true
- 其他的关于feign的配置之前的文章有提到,这里就不说了
规则的持久化配置
- 一旦我们重启应用,Sentinel规则将消失
- 生产环境需要将配置规则进行持久化
- 将限流配置规则持久化进 Nacos 保存
依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
yaml
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
在nacos配置列表中添加对应的配置文件
熔断降级框架对比
参考
SpringCloud-2.0-周阳(22. 流量监控 - Sentinel)学习笔记
SpringCloud-2.0-周阳(23. 熔断降级 - Sentinel)学习笔记
|