Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

Sentinel 控制台包含如下功能:

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。

  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。

  • 规则管理和推送:统一管理推送规则。

  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

阿里云提供了 企业级的 Sentinel 控制台,应用高可用服务 AHAS,对外收费,比较贵,但是具备Sentinel 数据持久化功能,开源版是不具备该功能的,我们也可以对sentinel进行改造让他支持持久化。

实时监控

**监控接口的通过的QPS和拒绝的QPS **。同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在”实时监控”下。

注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。

实时监控接口

实时监控截图

注意:请确保 Sentinel 控制台所在的机器时间与自己应用(服务)的机器时间保持一致,否则会导致拉不到实时的监控数据。

簇点链路

簇点链路用来显示微服务所监控的API,簇点链路的信息是存储在客户端内存中的,Sentinel会去实时拉取客户端的资源状态,如果客户端服务器一旦重启,数据就会丢失。

数据视图

该页面有2种显示方式:树形视图、列表视图。

树形结构视图

树形结构视图

列表视图

列表视图

流控规则

image-20230411114752462

1)新增流控规则

image-20230411114816056

资源名:需要进行限流的资源对象

针对来源:流控来源,default 不区分调用来源

阈值类型:QPS、并发线程数

单机阈值:限流阈值

是否集群:如果是集群对象,这里要勾上,如果是单机,不勾

2)限流阈值类型

流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS。

QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。

并发线程数:1秒内能处理多少个线程

举个例子

QPS:假设一个请求响应时间是0.2秒,那么1秒的QPS就是5,如果我们设置1秒只允许5个请求的话,新的请求进来就就会被拒绝。

线程数:1秒内只允许5个线程,此时5个线程的时间窗口(运行周期,请求处理时间)是2秒,如果有新的请求进来会直接被拒绝,因为在1秒内5个线程都占满了。

3)QPS限流测试

image-20230411120015379

QPS单机阈值大于1,也就是我们1秒钟访问2次接口就会限流

访问测试:http://localhost:8080/springBootSentinelException

image-20230411120129779

如图所示,这个图是sentinel默认的流控提示,我们可以通过实现sentinel接口来自定义异常处理。

BlockException异常统一处理

springwebmvc接口资源限流入口在HandlerInterceptor的实现类AbstractSentinelInterceptor的preHandle方法中,对异常的处理是BlockExceptionHandler的实现类

image-20230411120749315

自定义BlockExceptionHandler 的实现类统一处理BlockException

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.javaxing.springsentineldemo.config;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
log.info("BlockExceptionHandler BlockException================"+e.getRule());

String result = "";

if (e instanceof FlowException) {
result = "接口限流了";

} else if (e instanceof DegradeException) {
result = "服务降级了";

} else if (e instanceof ParamFlowException) {
result = "热点参数限流了";

} else if (e instanceof SystemBlockException) {
result = "触发系统保护规则了";

} else if (e instanceof AuthorityException) {
result = "授权规则不通过";
}

//返回json数据
response.setStatus(500);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getWriter(), result);

}
}

再次访问测试:

image-20230411120649973

4)流控模式

流控模式分为3种:直接模式、关联模式、链路模式。

直接模式

资源调用达到设置的阈值后直接被流控抛出异常。

image-20230411120649973

关联模式

image-20230411145434040

关联模式:当关联资源达到流控阈值后,就对当前资源进行流控。

使用场景:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联,如在数据库中对同一个字段进行读操作和写操作的资源争抢,或如 当一台服务器连接到MySQL后,多个操作共同复用同一个连接,就会存在资源争抢。

使用关联模式可以让关联资源具备有更高的优先级,当关联资源达到了阈值,就会流控当前资源,来降低 关联资源的压力。

关联模式测试

我们接下来直接用jmeter来进行压测,每秒3个请求,请求接口 为 关联的资源接口,这样的话 当关联资源接口每秒超过2个QPS后,springBootSentinelException资源就会被限流。

image-20230411151335872image-20230411151512871

当我们开始压测关联资源(1秒3个QPS),我们在去访问springBootSentinelException接口,会直接提示限流。

image-20230411151548736

链路模式

Sentinel 链路模式 image-20230411162637833

新增链路模式

image-20230411163111642

当queryOrderInfo达到阈值QPS 2后,就会对 入口资源:test1 进行流控。这里和关联模式是反过来的。

链路模式失效问题

链路模式失效有2个主要原因:

1、高版本收敛链路

2、FlowException异常

高版本收敛链路问题

从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,导致链路限流不生效。

从1.7.0版本开始,官方在CommonFilter引入了WEB_CONTEXT_UNIFY参数,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流。

需要在yml中配置spring.cloud.sentinel.web-context-unify属性为false

1
2
 # 将其配置为 false 即可根据不同的 URL 进行链路限流
spring.cloud.sentinel.web-context-unify: false

FlowException异常

FlowException异常

原因分析:

  1. Sentinel流控规则的处理核心是 FlowSlot, 对getUser资源进行了限流保护,当请求QPS超过阈值2的时候,就会触发流控规则抛出FlowException异常
  2. 对getUser资源保护的方式是@SentinelResource注解模式,会在对应的SentinelResourceAspect切面逻辑中处理BlockException类型的FlowException异常

解决方案: 在@SentinelResource注解中指定blockHandler处理BlockException

1
2
3
4
5
6
7
8
@SentinelResource(value = "queryOrderInfo",blockHandler = "handleException")
public void queryOrderInfo(){
System.out.println("进入了订单查询详情");
}

public String handleException(Integer id, BlockException ex) {
return "被限流啦";
}

5)流控效果

当QPS超过阈值后,就会触发流控。流控的方式有三种:快速失败(直接拒绝)Warm UP(预热模式,平缓提升)匀速排队(排队等待)

  • 快速失败:达到阈值后,直接会拒绝并抛出FlowException异常
  • Warm UP:对于超过阈值的请求也是会拒绝并抛出异常,但是会阈值平缓上升,慢慢的提高阈值
  • 匀速排队:让所有的请求 进行排队消费,先进先出

快速失败

默认流控的处理方式,达到阈值后,直接会拒绝并抛出FlowException异常,适用于已经进行过压测,明确知道系统的处理能力。

Warm UP 预热模式

Warm UP 预热模式,为了避免突然大量的请求直接把系统打崩溃,我们可以采用预热模式。

通过Warm UP可以让流量缓慢增加,平缓提升到阈值的上限,给系统一个预热时间,避免一下子大量的请求把服务器打崩溃。

冷加载因子

codeFactor 默认是3,即请求 QPS 从 threshold(阈值) / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

举个例子:阈值如果设置10,那么这个阈值一开始就会被动态的调整成3,然后逐步增长,最终到达阈值上限 10 。

实验验证

image-20230411175407483

我们对springBootSentinelSuccess进行流控限制,流控效果为Warm Up ,让它在5秒内 缓缓的从3 动态过度到10

通过jmeter进行压测

image-20230411180200642

一开始的时候,10个请求只允许通过3个,丢弃7个,缓慢的平湖南上升,直到阈值上限。

image-20230411180852876image-20230411180912764

实时监控

匀速排队

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

时间轴

匀速排队:所有处理不了的请求都会按顺序排队,慢慢的进行消费,直到队列清空。

如果一下子请求太多,我们无法处理的话,默认情况下会拒绝掉多余的请求,而如果我们不想拒绝掉无法处理的请求的话,我们可以让他进行排队等待,等待可以处理的时候在进行消费。

注意:超时时间不可以太短,太短的话会导致排队的请求来不及处理就被拒绝了。

注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

实验验证

流控规则

image-20230412163013039

JMeter 压测

image-20230412163059840

压测结果

image-20230412163334787

每秒13个请求,但是只允许通过10个请求,还有3个请求会进入排队,以此类推。

熔断规则

1)慢调用比例

image-20230413110627891

最大RT:单个请求最长的响应超时时间

熔断时长:对该资源的熔断时长

统计时长:时间窗口的延迟 ,默认1秒,我们一般也是以1秒为单位

比例阈值:触发熔断的个数比例,如 最小请求5个,阈值0.6,那么触发熔断的个数最少必须达到3个(5*0.6)

最小请求数:触发熔断器的最小请求数量

达到慢调用熔断的限制必须满足2个条件:

  1. 触发熔断的个数必须达到 比例阈值
  2. 统计时长必须超过最小请求数

慢调用实验验证

controller

1
2
3
4
5
6
@GetMapping("/springBootSentinelSuccess")
public String springBootSentinelSuccess() throws InterruptedException {
// 模拟代码异常
Thread.sleep(200);
return "正常的业务逻辑执行...";
}

我们在controller里面延时200毫秒,请求该接口的延时必然会超过熔断策略RT时间

JMeter压测

image-20230413115306707

image-20230413115549271

如图所示,前面请求正常,随着业务逻辑时间超过RT的次数后,就触发熔断策略。

image-20230413115733051

当下一个请求进入sentinel后,会判断状态是否为open状态,如果是,就判断 当前时间是否超过 熔断时间(超时时间),如果超过就把状态变成halfOpen状态 并进入业务逻辑。

这也是为什么 突然有一个请求可以通过 并执行业务逻辑的原因。

慢调用熔断器的源码执行流程

  1. 当一个请求进入服务器后,会先被sentinel管控
    • 如果不符合熔断规则,直接放行
    • 如果符合了熔断规则,熔断器就会从close状态变成 open状态
  2. 当下一个请求进入sentinel后,会判断状态是否为open状态
    • 如果是,就判断 当前时间是否超过 熔断时间(超时时间)
      • 如果超过就把状态变成halfOpen状态 并进入业务逻辑
      • 如果不超过,返回false执行熔断
    • 如果不是,就返回 flase 执行熔断
  3. 当业务逻辑执行结束后判断 业务执行的时间是否 超过熔断阈值
    • 如果超过了,就会把熔断器从halfOpen变成open状态
    • 如果没有超过,就把熔断器都变成close 状态

慢调用源码分析

image-20230412171256694

进入cb.tryPass(context)方法

image-20230412172334273

retryTimeoutArrived方法

image-20230412172439715

fromOpenToHalfOpen方法

image-20230412172813154

当业务逻辑结束后,会执行exit方法

image-20230413105015170image-20230413105044806image-20230413105318835

2)异常比例

  • 在统计时间内异常请求次数超过比例阈值就会触发熔断器。
image-20230413141455973

比例阈值:如 0.6,那么在1秒内(统计时长) 异常数量达到3个就会触发熔断器。(5*0.6)

1
2
3
4
5
6
7
8
9
10
11
AtomicInteger atomicInteger = new AtomicInteger();

@GetMapping("/springBootSentinelException")
public String springBootSentinelException() {
atomicInteger.getAndIncrement();
if(atomicInteger.get() % 2 ==0){
// 模拟代码异常
int a = 1 / 0;
}
return "正常的业务逻辑执行...";
}

JMeter压测

image-20230413142341102

3)异常数

  • 在统计时间内异常请求次数超过阈值就会触发熔断器。
image-20230413142358381

在统计时长(10秒)内,最少有5个请求并且有3个请求异常,就会触发熔断器。

JMeter压测

image-20230413142841469

热点规则

1)什么是热点规则

我们把经常被访问的数据称为 热点数据,如果我们需要对热点数据设置流控的话,可以对其设置 热点策略。

热点规则流控

同一个请求 resA,携带的参数不同 有 axb、abc、xs,我们可以根据携带的参数进行流控

注意:

  1. 热点规则需要使用@SentinelResource(“resourceName”)注解,否则不生效,尤其是controller上做热点规则是不会生效的
  2. 参数必须是7种基本数据类型才会生效

2)实验验证

1.1 @SentinelResource设置sentinel资源

我们为springBootSentinelSuccessHotData 设置成sentinel资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@SentinelResource(value = "springBootSentinelSuccessHotData",
blockHandler = "handleException",
fallback = "fallbackException")
@GetMapping("/springBootSentinelSuccessHotData")
public String springBootSentinelSuccessHotData(@RequestParam("orderId") Integer orderId) throws InterruptedException {
// 模拟代码异常
return "正常的业务逻辑执行...";
}


public String handleException(BlockException ex) {
return "被流控了";
}

public String fallbackException(Throwable t) {
return "被异常降级了";
}

1.2 设置热点策略

image-20230413153353389image-20230413153726138

1、资源名为springBootSentinelSuccessHotData 的参数索引0(第一个参数),1秒内只允许访问3次,超过就会触发流控

2、由于添加了额外策略,该策略限制:当第一个参数为10086并且类型必须为int,符合策略的1秒内只允许访问1次

实验测试

  • id为10086的 1秒内只允许访问一次

测试结果

image-20230413154134751

系统规则

尽管我们做了很多策略,如 熔断策略、流控策略,但是当高并发大流量进入的时候,服务器负载太高处理不过来,为了避免服务器宕机,我们可以设置 系统规则策略,来保护机器的一个正常运行。

系统保护规则是从应用级别的入口流量进行控制,系统保护是保护整个应用级别,而并非应用下的某个资源。

规则策略有四个维度:Load、RT、入口 QPS 和线程数。

系统规则阈值类型

  • 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 达到阈值即触发系统保护。

举个例子:

image-20230413174456132

image-20230413174731646

授权控制规则(来源访问列表)

很多时候,我们需要根据调用者服务器来判断请求是否放行,此时我们就可以通过sentinel 来确定是否放行该服务器的请求。

image-20230413175235169

授权控制规则有2个名单:白名单、黑名单。

1)配置授权规则

授权规则
  • resource:资源名,即限流规则的作用对象。
  • limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB。
  • strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。

我们可以根据资源名,去授权 调用的应用服务器名称,授权时 可以加入到白名单或黑名单。

若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

2)实现sentinelRequestOriginParser接口

由于sentinel并没有完善获取origin 来源的方法,所以我们需要自行完善。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;


@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;
}
}

这里的serviceName 我们采取的是通过get 参数的形式携带过来,实际上可以通过很多种方式获得,这个可以自行拓展,主要是要告知sentinel 你的调用origin来源服务名即可。

集群流控规则

  • 开源版的sentinel 集群流控是不完善的,这里并不推荐,如果需要使用该功能,需要自行修改开源源码完善该功能。
    • 为什么不完善,完善的话,还要商业版的干嘛?

为什么要使用集群流控呢?假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判断是否可以调用。这就是最基础的集群流控的方式。

另外集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。

https://github.com/alibaba/Sentinel/wiki/%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7

集群流控中共有两种身份:

  • 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 给集群提供流控服务。

0

  • 嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。

0

云上版本 AHAS Sentinel 提供开箱即用的全自动托管集群流控能力,无需手动指定/分配 token server 以及管理连接状态,同时支持分钟小时级别流控、大流量低延时场景流控场景,同时支持 Istio/Envoy 场景的 Mesh 流控能力。