Sentinel源码—1.使用演示和简介一

大纲

1.Sentinel流量治理框架简介

2.Sentinel源码编译及Demo演示

3.Dashboard功能介绍

4.流控规则使用演示

5.熔断规则使用演示

6.热点规则使用演示

7.授权规则使用演示

8.系统规则使用演示

9.集群流控使用演示

1.Sentinel流量治理框架简介

(1)与Sentinel相关的问题

(2)什么是流量治理

(3)流量治理的手段

(4)Sentinel的核心功能

(5)总结

(1)与Sentinel相关的问题

**问题一:**在调用第三方接口或其他部门的接口时需要控制速度。例如第三方接口限制QPS为1000,需要在请求第三方接口时进行限流。

**问题二:**服务存在被大流量打垮的可能,为了保护服务就需要流量治理,防止恶意攻击导致服务崩溃。

**问题三:**当达到限流或错误比例阈值时,要进行熔断降级来保护服务的可用性。

**问题四:**限流的算法、熔断降级的原理

(2)什么是流量治理

**情况一:**服务部署了3台机器,每台机器配置为4C8G。当一千万的并发流量涌进来时,服务显然不能正常运行。如果不进行流量治理,整个系统会出现大量超时的情况。甚至会将3台服务器的CPU 、内存和带宽等指标瞬间打满,导致系统崩溃。所以,限流是非常重要的一种流量治理手段,可避免系统负载过高而崩溃。

**情况二:**如果服务出现了大量错误日志,而此时还有大量用户在不停地请求。那么只会导致更多的错误,加重系统的负载,最终导致系统崩溃。为了避免这种情况发生,可以使用熔断这个流量治理手段。将故障节点从系统中断开,从而保证整个系统的稳定性和可用性。

**情况三:**在进行熔断后,通常还需要降级。根据业务需求的不同,可以选择降级到其他方案或直接返回错误提示。通过这种方式,可以减轻系统负担,保证服务的可用性。

**总结:**限流、熔断、降级可有效控制网络流量,保证服务稳定和提升用户体验。假设服务能够抗1W的QPS,但突然来了10W的QPS,此时服务必然崩溃。如果也没有设置限流、熔断、降级策略,那么所有请求都无法正常处理。但是如果设置了限流、熔断、降级策略,那么至少可以保证每秒1W请求能够正常处理。

(3)流量治理的手段

一.限流(限流可以控制流量)

二.熔断(熔断可以防止故障节点影响整个系统)

三.降级(降级可以在系统过载时保证核心功能可用)

一.限流(限流可以控制流量)

限流是指对流量进行控制和限制,防止系统因流量过大而崩溃或无响应。限流可通过限制请求速率、并发数或者用户数量来实现,常见的限流算法有漏桶算法和令牌桶算法。

漏桶算法:

漏桶算法是一种比较简单的限流算法。它将请求看作水流,桶看作系统。每个请求进入系统就像水流进入桶里一样。当桶满时,多余的请求将会被丢弃。漏桶算法可通过控制漏出速率实现对请求速率的控制。

令牌桶算法:

令牌桶算法也是一种常见的限流算法。它将每个请求看作一个令牌,桶看作一个存放令牌的容器。在一定时间内,桶中可以存在一定数量的令牌。每当有一个请求进入系统时,就会消耗一个令牌。当令牌用完时,请求就会被拒绝。令牌桶算法可以通过控制令牌生成速率,实现对请求速率的控制。

限流的应用场景:

假设某服务部署了3台机器,每台机器能扛500QPS,总共可以抗1500QPS。现在突然由于促销活动来了一大批用户同时访问,可能达到3000QPS。但由于整个服务只能扛1500QPS,所以此时会把每台服务器都直接打挂。虽然可以通过加服务器来解决,但什么时候该加、什么时候不该加呢?所以需要采取限流策略来保证服务的稳定性。一种常见的限流策略就是:超过1500QPS后进来的请求直接拒绝或排队等待。比如将请求放入一个消息队列中,按照队列的先后顺序进行处理。如果队列中的请求超过一定数量或者等待时间超过一定阈值,则直接拒绝新的请求,从而避免服务器的过载。

二.熔断(熔断可以防止故障节点影响整个系统)

熔断是指在系统出现故障或异常时,将异常或故障的节点从系统中断开。比如将请求路由到备用节点或直接返回错误信息,从而保证系统稳定可用。

熔断通常是基于断路器模式(一种常见的故障处理模式)实现的。在断路器模式中,系统会维护一个断路器状态。当系统出现故障或异常时,会将断路器状态设置为打开状态。处理请求时如果发现断路器状态是打开状态,则将请求路由到备用节点或返回错误信息。当故障或异常解决后,断路器状态会重置为关闭状态,系统恢复正常。

熔断的应用场景1:

假设某服务部署了3台服务器,它们都连接到了网关。当请求流入系统时,若发现某台服务器持续出现请求超时现象。那么就会启动熔断机制,将这台服务器从请求流中剔除,从而确保流量被正确地分配到正常运行的服务器上。

熔断的应用场景2:

假设需要请求一个第三方API。如果该API持续超时,可能导致整个系统运行缓慢并占用大量线程资源。为解决这个问题,可以采用熔断策略,暂时停止对这个第三方API的请求,直接返回错误信息。这样,在一定时间内不再请求这个API,从而保护系统的稳定性和效率。

熔断的应用场景3:

假设程序操作数据库时,出现数据库连接池被耗尽或者数据库故障等情况,那么就会导致数据库操作失败或连接超时。如果此时不采取任何措施,就会有大量的线程在阻塞等待。从而导致服务器的负载增大,甚至可能引起级联故障。为了避免这种情况引起的级联故障,可以采用熔断策略。比如当数据库操作连续出现一定数量的错误或超时时,可将熔断器打开。程序发现熔断器打开后,立即返回错误提示,如"服务器正在维护"等,从而避免大量请求继续对数据库操作造成的影响。等数据库恢复后,再关闭熔断器,恢复正常的数据库操作。

三.降级(降级可以在系统过载时保证核心功能可用)

降级是一种应对高负载或故障的策略。当服务无法正常工作时,系统会自动降低服务的质量,以保持其可用性。降级可以通过简化输出、使用缓存数据或关闭非关键功能来实现。

降级的应用场景1:

节日大促会推很多热门商品,这些热门商品会有大量用户同时访问商情页。以淘宝、京东的用户体量来看,很可能会由于并发太高导致系统崩溃。为了避免这种情况,可以采用服务降级策略。比如仅展示商品的基本信息,避免加载评论等其他耗时操作,保证稳定。也就是说,牺牲部分非核心功能的可用性来保障核心功能的稳定性。

降级的应用场景2:

当接口出现大量报错时,很可能是由于访问数据库超时所致。为了避免因此而导致系统崩溃,我们可以采用服务降级的策略。比如当一个数据库出现故障时,可以降级到另一个可用的数据库,或者降级到其他存储介质。虽然数据可能不是完整的或者最新的,但至少可以保证服务正常提供请求。

(4)Sentinel的核心功能

Sentinel的核心功能主要包括以下三个方面:

一.流量控制

通过设置Sentinel的限流阈值,控制流入系统的请求流量,保护系统稳定。Sentinel支持多种限流模式,如QPS、并发线程数、响应时间等,也支持基于白名单、黑名单等维度的流量控制。

二.服务熔断

当服务持续出现异常时,可通过Sentinel的熔断机制拒绝请求或快速失败。避免将异常扩散到整个系统,保障系统的健康运行。比如服务出现故障时,可以通过熔断降级,快速停止对该服务的请求。并返回相应的错误提示信息,避免对整个系统造成影响。其中,熔断的策略可基于异常比例、异常数等,同时也支持自动恢复和手动恢复。

三.服务降级

当服务出现异常或超时时,可以通过Sentinel的降级机制,自动将请求切换到降级方法上。降级方法可以直接返回错误码,也可以写其他逻辑,以此保证系统可用。降级的策略可基于异常比例、异常数等,同时支持自动恢复和手动恢复。

除了这些核心功能,Sentinel还支持实时监控服务的流量和性能指标。这些指标包括请求量、响应时间、错误率等,并提供可视化的监控面板。Sentinel还支持规则配置、自定义流量控制等,从而能够实现个性化的流量治理。

(5)总结

不管是限流还是熔断和降级,都是用来控制和保障系统的稳定性和可靠性。

一.限流

通过限制请求速率、并发数或者用户数量来控制系统的流量,防止系统因为流量过大而崩溃或发生无响应的情况。要实现单点限流,可以使用Sentinel。要实现分布式限流,可以使用Nginx、Redis、Sentinel集群(支持不是太友好)。

二.熔断

在系统出现故障或异常时将故障节点从系统中断开,从而保证系统可用。

三.降级

在系统过载的情况下保证核心功能的可用性。

熔断和限流的区别:

熔断针对故障节点,将故障节点从系统中断开。

降级针对整个系统,在系统过载时关闭非核心功能。

2.Sentinel源码编译及Demo演示

(1)源码部署

(2)Demo演示

(1)源码部署

一.下载Sentinel源码

二.解压缩和编译Sentinel源代码

三.将编译完成的源码导入到IDEA

四.启动Sentinel Dashboard源码

五.访问Sentinel Dashboard的控制台界面

一.下载Sentinel源码

比如下载Sentinel-1.8.6.zip。

二.解压缩和编译Sentinel源代码

注意需要使用较新版本的maven,比如apache-maven-3.8.8。

复制代码
cd Sentinel-1.8.6
mvn clean install -DskipTests -Dmaven.javadoc.skip=true

编译成功后的结果如下:

复制代码
[INFO] Reactor Summary for sentinel-parent 1.8.6:
[INFO] 
[INFO] sentinel-parent .................................... SUCCESS [  1.000 s]
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

三.将编译完成的源码导入到IDEA

四.启动Sentinel Dashboard源码

打开DashboardApplication类,然后启动该类的main方法,将看到如下的启动日志。

复制代码
com.alibaba.csp.sentinel.dashboard.DashboardApplication

五.访问Sentinel Dashboard的控制台界面

输入http://localhost:8080即可,用户名密码都是小写sentinel。

(2)Demo演示

一.启动sentinel-demo-annotation-spring-aop

二.调用接口进行测试

三.观察Sentinel控制台发现baz接口已注册进来

四.对接口进行限流

五.对接口进行熔断

Sentinel已为我们提供了sentinel-demo模块,其中包含了各种Demo。例如和Dubbo整合的、和okhttp整合的、和Gateway整合的等等。而且前面已经编译好了此模块,因此可以直接启动这些Demo应用。

一.启动sentinel-demo-annotation-spring-aop

该模块的main方法的路径为:

复制代码
com.alibaba.csp.sentinel.demo.annotation.aop.DemoApplication#main

启动之前需要添加JVM参数:

启动正常会输出如下日志:

二.调用接口进行测试

复制代码
com.alibaba.csp.sentinel.demo.annotation.aop.controller.DemoController

已经提供了两个测试接口:

复制代码
https://localhost:19966/foo
http://localhost:19966/baz/{name}

因此,可以直接调用如下接口进行测试:

复制代码
http://localhost:19966/baz/ctw

三.观察Sentinel控制台发现baz接口已注册进来

项目启动后,如果没有访问项目的资源,Sentinel控制台里是看不到的。也就是说Sentinel控制台是懒加载的,只有访问了资源才会在控制台看到。

截图中的资源名称为什么是helloAnother而不是baz,因为这个资源名称是通过注解自定义的,在TestServiceImpl实现类里就定义了资源名称为helloAnother。

复制代码
@RestController
public class DemoController {
    @Autowired
    private TestService service;
    
    @GetMapping("/baz/{name}")
    public String apiBaz(@PathVariable("name") String name) {
        return service.helloAnother(name);
    }
}

@Service
public class TestServiceImpl implements TestService {
    ...
    @Override
    @SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback", exceptionsToIgnore = {IllegalStateException.class})
    public String helloAnother(String name) {
        if (name == null || "bad".equals(name)) {
            throw new IllegalArgumentException("oops");
        }
        if ("foo".equals(name)) {
            throw new IllegalStateException("oops");
        }
        return "Hello, " + name;
    }
    ...
}

四.对接口进行限流

给下面的接口配置的限流规则为:每秒能接收的QPS为1,如果超出后则采取快速失败策略。同样的,还有排队等待策略和Warm Up策略,这里先演示快速失败策略。

复制代码
http://localhost:19966/baz/{name}

给接口配置完限流规则后,再快速多次访问这个接口看看效果。可以发现限流策略已生效,每秒只能访问1次,超出1次则直接返回失败。

五.对接口进行熔断

由于熔断降级的触发条件是基于错误比例和错误数或者是基于响应时长,所以要想实现熔断降级的效果需要先在DemoController中新增sleep接口。

这个sleep接口每次访问都睡眠3秒钟,即一次访问要3秒才能返回结果。使用@SentinelResource对该接口配置了一个资源名称叫sleep,并且配置了失败降级后调用方法是sleepFallback()方法。也就是正常返回Sleep,熔断降级后返回Sleep Failed。

复制代码
@RestController
public class DemoController {
    @Autowired
    private TestService service;
    
    @GetMapping("/foo")
    public String apiFoo(@RequestParam(required = false) Long t) throws Exception {
        if (t == null) {
            t = System.currentTimeMillis();
        }
        service.test();
        return service.hello(t);
    }
    
    @GetMapping("/baz/{name}")
    public String apiBaz(@PathVariable("name") String name) {
        return service.helloAnother(name);
    }
    
    @GetMapping("/sleep")
    @SentinelResource(value = "sleep", defaultFallback = "sleepFallback")
    public String sleep() throws InterruptedException { 
        TimeUnit.SECONDS.sleep(3);
        return "Sleep";
    }
    
    public String sleepFallback() throws InterruptedException {
        return "Sleep Failed";
    }
}

接口定义好后,需要先调用一次此接口http://localhost:19966/sleep。因为Sentinel控制台是懒加载,所以需要先调用接口,对应接口才能出现在控制台。当调用完成后,就可以如下所示创建熔断降级的规则了。

下图配置的规则是:sleep这个资源响应时长如果超过1000ms就熔断5s,5s后自动关闭熔断。配置完规则后,就可以多访问几次sleep接口验证效果了。会发现当第二次访问sleep接口时就调用了降级方法返回Sleep Failed。

3.Dashboard功能介绍

(1)实时监控

(2)簇点链路

(3)流控规则

(4)熔断降级规则

(5)热点规则

(6)系统规则

(7)授权规则

(8)集群流控

(9)机器列表

Sentinel Dashboard是Sentinel提供的一款可视化监控和管理平台。通过这个平台,可以实时监控、配置和管理Sentinel的各种功能。Sentinel Dashboard的概览如下图所示,需要注意的是:Sentinel Dashboard是懒加载的。

(1)实时监控

Sentinel Dashboard具备实时监控的功能,可以查看应用的各项指标。例如QPS、响应时间、通过请求、拒绝请求等。如下展示的就是实时监控一些指标的折线图和表格。

**应用场景一:**在高并发场景下,可以实时监控帮助了解系统的情况,以便及时采取措施防止系统过载。

**应用场景二:**在系统出现问题时,可以通过实时监控迅速定位问题,缩短故障处理时间。

(2)簇点链路

Sentinel Dashboard支持查看簇点链路,以展示当前应用的资源以及每个资源的实时指标和不同的操作。展示资源的实时指标包括QPS、并发数、RT等。

**应用场景一:**查看系统中所有资源的实时指标,以便更好了解系统的运行状况。

**应用场景二:**某个资源需要进行限流、降级、系统保护等时,可在该界面进行操作。

(3)流控规则

通过Sentinel Dashboard,可以轻松配置流量控制规则。此菜单功能很强大,因为流控的规则有很多,比如按照QPS维度、并发线程数维度进行流控。不光流控维度多,流控的模式和效果也很丰富,比如触发流控规则后可以实现快速失败、排队等待、Warm Up冷启动(预热)。

流控规则界面如下图示:

**应用场景一:**在秒杀活动等高并发场景下,可以设置限流规则,保证系统稳定运行。

**应用场景二:**在请求第三方接口时,比如遇到第三方接口有QPS限制,可以设置合理的QPS阈值,以此来保证调用成功率。当然还可采取排队等待策略让超出部分不直接拒绝,而是排队等待请求。

(4)熔断降级规则

Sentinel Dashboard支持配置熔断降级规则,比如按照每秒慢调用的比例、每秒异常比例、每秒异常个数来配置熔断降级规则,以保护应用在出现异常时,不会对整个系统造成影响。

熔断降级界面如下图示:

**应用场景一:**在微服务架构中,当一个服务出现问题时,可以通过配置熔断降级规则,防止故障扩散,保护整个系统的稳定性。

**应用场景二:**在调用第三方API时,可以配置熔断降级规则,避免因为第三方API的不稳定导致自身系统的不稳定。

(5)热点规则

Sentinel Dashboard支持配置热点规则,以限制参数的热点值。可以针对不同参数值做不同的流控规则,流控规则细粒度到参数上。这对某些中台业务很有用处,从而避免参数异常导致的系统压力。

热点规则界面如下图示:

**应用场景一:**对于存在高并发访问特定参数值的场景,可配置热点规则降低该参数值对系统的压力。

**应用场景二:**对于某些参数值可能导致系统功能异常的场景,可配置热点规则限制该参数值的访问量。

上述两种场景都是针对某个参数细粒度限流用的,比如某个接口的某个名为app的参数代表了来自不同业务方的调用,那么可以配置不同参数值有不同的流控规则:参数app=1时的QPS限制为10,参数app=2时的QPS限制为20。

(6)系统规则

Sentinel Dashboard支持配置系统规则。Sentinel会自动检测当前系统的各项指标,比如CPU使用率、入口QPS等。如果发现超过负载值则抛异常,实现系统出现异常时对资源限制或降级。

系统规则界面如下图示:

**应用场景一:**在系统资源不足时,通过配置系统规则,实现资源的合理分配,保证系统稳定运行。

**应用场景二:**对于系统中易出现异常的资源,可能RT较长、线程数不允许过多、入口QPS允许较少,通过配置系统规则,防止资源异常导致系统崩溃。

(7)授权规则

Sentinel Dashboard支持配置系统规则,目前主要针对黑名单和白名单两种策略对资源进行限制。

授权规则界面如下图示:

**应用场景一:**发现接口被某个IP或某个userId刷了,那么可以将此IP或者userId加入黑名单,这样它就无法继续访问了。

**应用场景二:**系统仅仅允许公司高管登录,那么可以将高管的userId放入白名单,这样其他用户就无法访问系统。

(8)集群流控

Sentinel Dashboard支持集群流控规则。集群流控规则主要用于在分布式系统中实现整体流控而不是单机流控。比如一个服务部署了10台机器,需要对某接口整体限流100QPS。也就是10台机器一共限流100QPS,这时就需要集群限流了。集群限流的目的是防止服务提供方在整体上超过其处理能力。

集群规则界面如下图示:

**应用场景一:**保护服务提供方,当服务调用方的请求量超过提供方的处理能力时,限制整体流量。

**应用场景二:**资源控制,在分布式系统中,通过集群流控规则可以确保整体资源不会被过度使用。

(9)机器列表

Sentinel Dashboard支持查看应用中所有机器的列表。可以查看每个机器的IP地址、端口号、Sentinel客户端版本、当前服务时候健康以及最后一次心跳的时间,以便于管理和监控。

机器列表界面如下图示:

(10)总结

Sentinel Dashboard是一个功能强大的可视化管理和监控平台,它针对分布式系统提供了一系列实用的工具和功能。

通过Sentinel Dashboard,可以轻松地管理:流控规则、熔断降级规则、热点参数限流规则、系统规则、黑白名单授权规则以及集群流控规则等,实现对分布式系统中各种资源的精细化管理和保护。

Sentinel Dashboard还提供了实时监控和统计功能,使得开发者能实时了解系统的运行状态,识别系统中的瓶颈和潜在问题。

4.流控规则使用演示

(1)流控方式(QPS和线程数)

(2)流控效果(快速失败、排队等待、预热)

(3)流控模式(关联模式和链路模式)

Sentinel提供了多种流控方式,可以根据QPS、根据线程数进行流控等。而且这些流控方式还有丰富的效果选项,如快速失败、排队等待、预热。

(1)流控方式(QPS和线程数)

一.按QPS流控

新建一个名为sentinel-study-demo的项目,然后添加Sentinel相关依赖以及Springboot依赖,pom.xml文件如下:

复制代码
<groupId>com.demo.sentinel</groupId>
<artifactId>sentinel-study-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>

<dependencies>
    <!-- sentinel 核心依赖 -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-core</artifactId>
        <version>1.8.6</version>
    </dependency>

    <!-- 将自己项目和 sentinel-dashboard 打通的依赖 -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-transport-simple-http</artifactId>
        <version>1.8.6</version>
    </dependency>

    <!-- springboot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.3.11.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

启动入口如下:

复制代码
@SpringBootApplication
public class StudyDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudyDemoApplication.class, args);
    }
}

application.propertites配置文件如下:

复制代码
spring.application.name=sentinel-study-demo
server.port=19966

接下来,将sentinel-study-demo项目与Sentinel Dashboard进行集成,以便在Sentinel Dashboard上展示该项目的流控规则和监控信息。上面已在pom.xml文件添加了Sentinel Dashboard的依赖,但还不够。因为该项目并不知道Sentinel Dashboard服务器的IP地址和端口,所以无法正确连接到Sentinel Dashboard服务。

为此,需要在该项目中配置Sentinel Dashboard的地址和端口信息,告知sentinel-study-demo项目如何连接到正确的Dashboard服务。

通过以下配置可以实现这一目标:

复制代码
 -Dcsp.sentinel.dashboard.server=localhost:8080

由于Sentinel Dashboard是懒加载的,因此上述配置只是简单地将项目与Sentinel Dashboard进行打通,并不能立即在Sentinel Dashboard页面上显示出项目信息。为了使项目在Sentinel Dashboard页面上正常展示,还需要添加一个接口来配置Sentinel的资源,并访问这个接口。如下所示:

复制代码
package com.demo.sentinel.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/qps")
public class TestQpsController {
    @GetMapping
    public String testQps() {
        try (Entry entry = SphU.entry("testQps")) {
            //被保护的逻辑
            return "success";
        } catch (BlockException ex) {
            //处理被流控的逻辑
            return "blocked";
        }
    }
}

上述代码使用了SphU.entry("testQps")来标识这是一个Sentinel资源,即SphU.entry("testQps")会建立一个名为testQps的Sentinel资源。我们可以针对此资源名称进行流控、降级等配置。如果超出了配置的阈值,则会抛出BlockException,返回blocked。如果没超出配置的阈值,则会正常返回success。

然后,启动sentinel-study-demo项目并访问http://localhost:19966/qps。然后访问Sentinel-Dashboard控制台http://localhost:8080,会发现testQps资源已同步并显示到Sentinel Dashboard控制台中。

接着,在Dashboard上建立一个资源名为testQps的流控规则,也就是针对testQps这个资源建立一个QPS为1的流控配置。并设置流控效果为快速失败,这意味着这个接口在一秒内只能被访问一次。超过一次的请求将被立即拒绝,即抛出BlockException异常。这个异常会被代码里的try catch块捕获,最终返回blocked作为响应。

二.按线程数流控

按线程数流控的意思是,比如设置接口所允许的最大线程数是3,那么超出3个线程在同时运行后,新创建的线程将被拒绝。

首先,在上面已创建的项目里添加如下接口:

复制代码
package com.demo.sentinel.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/thread")
public class TestThreadController {
    @GetMapping
    public String testThread() {
        try (Entry entry = SphU.entry("testThread")) {
            //被保护的逻辑
            return "success";
        } catch (BlockException ex) {
            //处理被流控的逻辑
            return "blocked";
        }
    }
}

由于Sentinel Dashboard是懒加载的,因此需要手动请求这个接口才能使其在Sentinel Dashboard上加载出来,然后针对testThread这个资源建立了一个并发线程数为3的流控配置。如下图所示:

可发现截图中并没有地方配置流控效果,如快速失败、预热、排队等待。这是因为并发线程数类型的流控规则主要是用来限制并发请求数量的。

我们可以创建不同类型的流控规则来实现不同的流控策略。例如可以创建一个QPS类型的流控规则,用于限制每秒请求数量。同时还可以创建一个线程数类型的流控规则,用于限制并发线程数。这些规则的组合将会影响最终的流控策略。

虽然Sentinel Dashboard没地方配置按照并发线程数类型的流控效果,但是按照并发线程数类型的流控规则的流控效果默认就是快速失败。

这意味着http://localhost:19966/thread接口只能同时存在3个线程在执行。超过3次后的请求将被立即拒绝,即抛出BlockException异常。这个异常会被try catch块捕获,最终返回blocked作为响应。为了助于演示效果,可以在代码块中加个Sleep,如下。这时,借助JMeter工具进行多线程并发测试。配置5个线程并发访问,按照配置会有2个线程失败,3 个线程成功。

复制代码
package com.demo.sentinel.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/thread")
public class TestThreadController {
    @GetMapping
    public String testThread() {
        try (Entry entry = SphU.entry("testThread")) {
            //被保护的逻辑
            Thread.sleep(5000); // 5s
            return "success";
        } catch (BlockException ex) {
            //处理被流控的逻辑
            return "blocked";
        }
    }
}

(2)流控效果(快速失败、排队等待、预热)

一.快速失败

就是在超出配置的阈值后直接抛出BlockException异常,不做任何逻辑,快速失败也被称为直接拒绝。

二.排队等待

在Sentinel中,可以通过设置排队等待来控制当超出配置的QPS阈值后,不是直接拒绝请求,而是让请求进入队列排队,从而实现更平滑的流量控制。这样可以避免瞬间大量请求导致服务不可用,也尽最大可能避免请求丢失。

下面新建一个接口:

复制代码
http://localhost:19966/qps/wait

package com.demo.sentinel.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/qps")
public class TestQpsController {
    @GetMapping
    public String testQps() {
        try (Entry entry = SphU.entry("testQps")) {
            //被保护的逻辑
            return "success";
        } catch (BlockException ex) {
            //处理被流控的逻辑
            return "blocked";
        }
    }
    
    @GetMapping("/wait")
    public String testQpsWait() {
        try (Entry entry = SphU.entry("testQpsWait")) {
            //被保护的逻辑
            return "success";
        } catch (BlockException ex) {
            //处理被流控的逻辑
            return "blocked";
        }
    }
}

接下来,在Sentinel Dashboard上配置流控效果为排队等待,如下图示。在配置前要先访问此接口,否则懒加载的Sentinel Dashboard不会显示。

下面配置的含义是:针对testQpsWait资源进行QPS最大为1的限制。如果超出了此限制,则进入排队等待模式,等待的时间为1秒。如果1秒内还没处理完,则抛出异常,相当于直接拒绝。也就是如果超出了配置的阈值,则会等待1秒钟,而不是直接拒绝,从而尽可能保证不丢失用户的请求。

三.预热

预热就是一种在系统启动阶段逐渐增加资源的流量控制阈值的策略。Warm Up的目的是让资源在启动时慢慢适应高流量的情况,而不是立即接受配置的最大并发请求量。这样可避免系统因突然的高并发而无法应对,导致出现的服务崩溃。

举个例子来说明Warm Up的作用:假设有一个Web服务器,它可以同时处理最多100个并发请求。在系统启动时,可将资源的初始QPS阈值设置得较低,例如10。然后在一个较短的时间段内(例如10秒)逐渐增加QPS阈值,直到达到配置的最大值100。

这样在服务器启动的初始阶段,只有较少的请求可以通过。并且服务器有足够的时间来逐渐升温,适应高并发的情况。一旦预热完成,服务器就可以稳定地处理更多的并发请求,而不会因为突然的高并发而导致性能问题或崩溃。

(3)流控模式(关联模式和链路模式)

有两种流控模式,分别是关联和链路。

一.关联模式

关联流控模式中,可以将两个资源进行关联。当某个资源的流量超限时,可以触发其他资源的流控规则。

比如用户下单购物时会涉及下单资源和支付资源。如果支付资源达到流控阈值,那么应该要同时禁止下单,也就是通过支付资源来关联到下单资源。

注意这里有个容易混淆的点:如果采取关联模式,那么设置的QPS阈值是被关联者的,而非关联者的。

如下图所示:下述配置了QPS阈值为3。这是针对testPay资源设置的,而不是针对testOrder资源设置的。也就是testOrder被流控的时机就是当testPay的QPS达到3的时候,3并不是testOrder所访问的次数,而是testPay接口被访问的次数。

二.链路模式

一个资源可能会被多个业务链路调用,不同的业务链路需要进行不同的流控,这时就可以使用链路模式。链路模式的使用例子如下所示。

首先,在pom.xml中新增依赖:

复制代码
<dependency>
    <!-- 可以使用@SentinelResource注解 -->
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.6</version>
</dependency>

<dependency>
    <!-- 可以使用限流的链路模式 -->
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.8.6</version>
</dependency>

然后,新增一个资源如下:之前定义资源都是采取SphU.entry("xxx")的方式,这里使用注解方式@SentinelResource来进行资源定义。

复制代码
package com.demo.sentinel.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

//资源,名为testTrace
@Service
public class TestTraceService {
    @SentinelResource("testTrace")
    public String testTrace() {
        return "testTrace";
    }
}

接着新增两个接口去调用这个资源:

复制代码
@RestController
@RequestMapping("/trace")
public class TestTraceController {
    @Autowired
    private TestTraceService testTraceService;

    @GetMapping("/test1")
    public String test1() {
        //调用名为testTrace的资源
        return testTraceService.testTrace();
    }

    @GetMapping("/test2")
    public String test2() {
        //调用名为testTrace的资源
        return testTraceService.testTrace();
    }
}

使用注解方式时需要引入sentinel-annotation-aspectj依赖。虽然前面已在pom.xml中新增了sentinel-annotation-aspectj依赖,但其实@SentinelResource("testTrace")注解还是不能起作用,所以还需要新增如下配置:

复制代码
@Configuration
public class DemoConfiguration {
    //使得@SentinelResource("testTrace")注解生效
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
    
    //使链路模式生效
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        //入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

至此,访问接口并刷新Sentinel Dashboard控制台便如下所示:

接下来就可以为testTrace资源创建链路模式的流控规则了。下图会为testTrace资源创建一个链路模式的流控规则:规则为QPS限制到1 ,且链路入口资源为/trace/test2。

这意味着:/trace/test1链路可以随便访问testTrace资源,不受任何限制。但是/trace/test2链路访问testTrace资源时会限制QPS为1,超出限制被流控。

(4)总结

一.两种流控方式

按照QPS进行流控以及按照线程数进行流控。QPS限制的是请求次数,线程数限制的是请求人数,两者可以同时结合起来使用。

二.三种流控效果

快速失败:也称为直接拒绝。当超出配置的流控阈值后,多余的请求将直接抛出Sentinel内部异常,这些多余的请求不会走到主业务逻辑当中。

**应用场景:**假设系统中有一个用户认证服务,限制每秒最多处理10个请求。当并发登录请求数超过10,新的登录请求会被快速失败,直接拒绝。从而避免认证服务被过多的登录请求压垮。归根结底就是避免系统被打垮,通过丢弃部分流量来保证系统稳定。

排队等待:排队等待不会将多余的请求马上拒绝,而是会排队等待一会。如果超出等待时长后请求还没得到处理的话,才会采取快速失败策略。

**应用场景:**比如在线购物平台的下单服务,库存检查是关键环节。假设系统中的库存检查服务,每秒最多处理50个请求,但可以排队等待。当下单请求超过50个时,新的下单请求会进入队列等待。等待一段时间后再处理,保护库存检查服务免受过多下单请求的冲击。同时避免直接拒绝请求,提高用户体验。

预热:也就是Warm Up。假设系统能接收10QPS,且设置的预热时长为3s。那么服务刚启动时第一秒可能仅能处理10 / 3 = 3个请求,第二秒可能能够处理6个请求,第三秒可能能够处理9个请求。逐步恢复正常的10QPS,能够接收的请求数会随着预热时长逐步上涨。

**应用场景:**新闻发布系统启动时,限制新闻发布服务每秒只能处理10个请求,然后逐渐增加。在系统启动时,可以通过预热功能,逐渐增加新闻发布服务的处理能力,让系统从冷启动过渡到正常负载,避免启动时系统压力过大,保证系统稳定。

相关推荐
东阳马生架构12 小时前
Sentinel源码—2.Context和处理链的初始化
sentinel
东阳马生架构1 天前
Sentinel源码—1.使用演示和简介二
sentinel
西岭千秋雪_2 天前
Sentinel核心算法解析の滑动窗口算法
分布式·算法·spring cloud·微服务·中间件·sentinel
張萠飛4 天前
Redis哨兵模式下执行sentinel failover mymaster命令可能导致什么风险,如何避免
redis·bootstrap·sentinel
小马爱打代码5 天前
Spring Cloud Alibaba微服务治理实战:Nacos+Sentinel深度解析
微服务·架构·sentinel
有梦想的攻城狮6 天前
spring-cloud-starter-alibaba-sentinel使用说明
linux·服务器·sentinel·springcloud
Kale又菜又爱玩7 天前
Sentinel全面解析与实战教程
java·spring·微服务·sentinel·springboot·springcloud
风铃儿~9 天前
Sentinel深度解析:微服务流量防卫兵的原理与实践
java·微服务·sentinel