Sentinel 分布式系统的流量防卫兵


  • 下载安装
    https://github.com/alibaba/Sentinel/releases/tag/1.8.6
    启动后默认端口为8080
  • 构建微服务:
    POM:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <dependencies>
    <!-- Springcloud ailibaba nacos -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--Springcloud ailibaba sentinel-datasource-nacos后续做特久化用到 -->
    <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <!--Springcloud ailibaba sentinel -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--openfeign-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--SpringBoot.整合web组件+actuator-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
    <version>1.9.0</version>
    </dependency>
    </dependencies>

YML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 8401

spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认为8719端口,假如8719被占用,会依次+1,直到找到未使用端口
port: 8719

management:
endpoints:
web:
exposure:
include: "*"

Sentinel采用的懒加载模式:也就是只有当微服务被访问时才会加载出来

流控规则


资源名:唯一名称,默认请求路径
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
阈值类型单机阈值:

  • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
  • 线程数:当调用该api的线程数达到阈值的时候,进行限流
    是否集群:不需要集群
    流控模式:
  • 直接:api达到限流条件时,直接限流
  • 关联:当关联的资源达到阈值时,就限流自己
  • 链路:只记录指定涟路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
    流控效果:
  • 快速失败:直接失败,抛异常
  • Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值
  • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

降级规则

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制
让请求快速失败,避免影响到其它的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

  • RT(平均响应时间,秒级)
    平均响应时间 超出阈值在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
    窗口期过后关闭断路器
    RT最大4900(更大的需要通过-Dcsp.sentinel..statistic.max.rt=XXXX才能生效)

  • 异常比列(秒级)
    每秒QPS>=5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

  • 异常数(DEGRADE_GRADE_EXCEPTION_COUNT)
    当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow小于60s,则结束熔断状态后好可能再进入熔断状态。

热点规则


限制你的参数访问量
资源名是否加斜线,将会对应到他是从GetMapping(rest地址)获取的还是从SentinelResource获取的(也就是作为唯一标识)

1
2
3
4
5
6
7
8
9
10
11
12
13
@GetMapping("/testHotKey")
@SentinelResource("testHotKey", blockHandler = "dealTestHotKey")
open fun testHotKey(
@RequestParam(value = "p1", required = false) p1: String?,
@RequestParam(value = "p2", required = false) p2: String?
): String {
return "test 测试热点数据"
}

open fun dealTestHotKey(p1: String?, p2: String? ,e:BlockException): String {

return "deal_hotkey"
}

兜底方法(也就是限流,熔断后的反馈方法{fallback})

从HystrixCommand到@SentinelResource
使用blockHandler必须保证后面还需要一个BlockException的参数

@SentinelResource
处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;
RuntimeException
int age= 10/0,这个是java运行时报出的运行时异常RunTimeException,@SentinelResource不管

系统规则

系统自适应限流:也就是将整个应用完全包裹起来,在应用外设置限流

系统保护规则是从应用级别的入口流量进行控制,从单台机器的Load、CPU使用率、平均RT、入口QPS和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如Web服务或Dubbo服务端接收的请求,都属于入口流量。
系统规则支持以下的模式:

  • Load自适应(仅对inux/Unix-like机器生效):系统的load1作为启发指标,进行自适应系统保护。当系统lod1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的max Qpsmint估算得出。设定参考值一般是CPU cores2.5。
  • CPU usage(1.5.0+版本):当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0),比较灵敏。
  • 平均RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。

详细SentinelResource讲解

解耦

统一的处理兜底方法:
使用blockHandlerClass来统一处理。

1
2
3
4
5
6
7
8
9
10
11
12
@SentinelResource(blockHandlerclass=CustomerBlockHandler.class,blockHandler="handlerException2"))
···

public class CustomerBlockHandler
{
public static CommonResult handlerException1(BlockException exception){
return new CommonResult(4444,"按客戶自定义,global hand1 erException---1");
}
public static CommonResult handlerException2(BlockException exception){
return new CommonResult(4444,"按客戶自定义,global handlerException---2");
}
}

服务熔断

sentinel整合ribbon+openfeign+fallback

  • fallback:解决运行时异常

    需要使用@PathVariable来获取参数
  • blockHandler:解决配置违规

可以同时配置fallback和blockHandler。但是blockHandler的优先级更高。

异常忽略

即不再帮助解决异常和错误问题。而是使用系统默认的解决方案

Feign

POM:

1
2
3
4
5
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

YML:

1
2
3
feigh:
sentinel:
enabled: true

主启动添加@EnableFeignClients

业务类:接口+注解
实现他的fallback类

规则持久化

每次重启微服务都会导致所有规则消失,因此需要配置持久化
所以把他保持到nacos中
POM:

1
2
3
4
5
<!--Springcloud ailibaba sentinel-datasource-nacos后续做特久化用到 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

YML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认为8719端口,假如8719被占用,会依次+1,直到找到未使用端口
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
data-id: cloudalibaba-sentinel-service
group-id: DEAULT_GROUP
data-type: json
rule-type: flow

然后在nacos中添加一个与上面data-id相同的配置,也就是application.name