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文件如下:

com.demo.sentinel
sentinel-study-demo
1.0.0-SNAPSHOT


    <!-- sentinel 核心依赖 -->
    
        com.alibaba.csp
        sentinel-core
        1.8.6
    

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

    <!-- springboot -->
    
        org.springframework.boot
        spring-boot-starter-web
        2.3.11.RELEASE
    



    
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    

启动入口如下:

@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中新增依赖:


    <!-- 可以使用@SentinelResource注解 -->
    com.alibaba.csp
    sentinel-annotation-aspectj
    1.8.6



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

然后,新增一个资源如下:之前定义资源都是采取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个请求,然后逐渐增加。在系统启动时,可以通过预热功能,逐渐增加新闻发布服务的处理能力,让系统从冷启动过渡到正常负载,避免启动时系统压力过大,保证系统稳定。

 

5.熔断规则使用演示

(1)案例说明熔断和降级

(2)Sentinel Dashboard中熔断规则的配置项

(3)熔断策略之慢调用比例

(4)熔断策略之异常比例和异常数

 

(1)案例说明熔断和降级

一.熔断

假设电商平台有多个库存服务实例,用于处理商品库存查询。有一个库存服务实例可能由于网络问题等原因而变得不稳定,为了避免该库存服务实例异常而影响整个服务,可以对该实例实施熔断。

 

在这种情况下,可以设定一个阈值。如果在一段时间内发现对该库存服务实例的请求有50%+是失败的,那么会触发熔断器,在一段时间内停止对该库存服务实例进行调用。这样这个异常的库存服务实例便不会影响到商品的库存查询业务了。

 

二.降级

假设电商平台有个商品推荐功能,它会根据用户浏览记录推荐相关商品。在大促期间,平台可能会遭受巨大流量冲击,导致服务响应时间变慢。为了避免影响核心功能,可以在高峰期间对商品推荐功能进行降级。这意味着系统只会提供基本的商品推荐,而不会使用复杂的推荐算法。这样虽然会降低用户体验,但可以确保平台的核心功能仍然可用。

 

通过熔断和降级机制,系统可以在节点不稳定或高负载情况下保持稳定。从而避免系统崩溃或性能下降,这是分布式系统中流量治理的重要实践。

 

熔断和降级往往都是结合一起使用的。针对单节点进行熔断的时候,适合单独使用熔断规则。针对所有节点进行熔断的时候,适合熔断 + 降级一起使用。

 

假设整个库存查询服务都出了问题,各个服务实例都触发了熔断。这时就可以考虑结合降级策略,确保系统依然能够提供基本的功能。

 

比如在库存查询的情况下,可选择的降级方案有:

 

方案一:降级到可靠介质

可以将查询库存的请求切换到查询备份数据库或其他可靠介质,这样虽然可能会降低性能,但仍然可以为用户提供基本的服务。

 

方案二:降级到限流方法

可以实施限流,即控制并发请求数,以避免过多的请求加重故障状况。例如实现一个每秒只允许处理一定数量的库存查询请求的方法,从而保护系统免受过载的影响。

 

(2)Sentinel Dashboard中熔断规则的配置项

资源名:就是通过SphU.entry("xxx")或@SentinelResource("xxx")定义的名称。

 

熔断策略:比如慢调用比例、异常比例、异常数。

 

最大RT:RT就是Response Time,即响应时间。当熔断策略为慢调用比例时会出现此选项,其他两种策略不会显示此选项,也就是当请求时间超出多少RT后会进行熔断。

 

比例阈值:当熔断策略配置慢调用比例时,该值为慢调用占所有请求的比例上限。当熔断策略配置异常比例时,该值为请求异常所占比例的上限。取值范围:0.0 ~ 1.0,小数其实就是百分比。比如配置0.1,则为10%,最大为1.0,也就是100%。

 

异常数:当熔断策略选择异常数时才会出现异常数选项,含义就是请求的异常数量。值得注意的是:Sentinel中异常降级的统计是仅针对业务异常,而Sentinel本身的异常也就是BlockException是不生效的。比如触发流控报异常了,那么是不会统计到异常数当中。

 

熔断时长:当达到熔断阈值后,会进入熔断状态。超出配置的熔断时长后会恢复到Half Open状态。也就是说当超出熔断时长后不会立即恢复,而是看新进入的请求是否正常。如果还是不正常,则继续熔断,反之恢复。

 

最小请求数:请求数目大于该值时才会根据配置的熔断策略进行降级。比如配置该值为10 ,但是请求一共才3个。那么即使比例阈值设置的100% ,熔断策略也不会生效的,因为没达到最小请求数。

 

统计时长:就是统计慢调用比例、异常比例、异常数时的时长。

(3)熔断策略之慢调用比例

慢调用比例,就是一个用于度量系统中慢速或延迟调用所占比例的指标。即在一定时间窗口内,慢速调用的数量与总调用数量的比例。

 

例如在过去的10秒内(统计时长),系统总共处理了100个调用,其中有10个调用的响应时间超过了1000毫秒(最大RT),那么慢调用比例就是10%。

 

下面的配置要达到的效果是:当资源testSlowCall在10秒(统计时长)内请求数达10个(最小请求数)以上,且响应时长超过1秒(最大RT)的请求数量大于1(10 * 0.1)个时进行熔断,熔断5秒后资源testSlowCall会变成Half Open状态。即5秒后的第一个请求如果没有问题则恢复正常,否则继续熔断。

同时针对上述配置会新增一个接口如下:即提供一个RT为3s的接口。接下来就可以实现慢调用比例的效果了,只需要在10s内(统计时长)请求testSlowCall资源10次(最小请求数)即可。由于第10次请求时发现RT已超1s,此时就会触发熔断并熔断时长为5s。这次请求被熔断后就不会进入主方法了,会直接返回默认的异常页。

@GetMapping("testSlowCall")
@SentinelResource(value = "testSlowCall")
public String testSlowCall() throws InterruptedException {
    //业务逻辑处理
    TimeUnit.SECONDS.sleep(3000);
    return "ok";
}

当然,被熔断后也可以通过@SentinelResource指定执行自定义的方法。其中@SentinelResource注解的fallback属性,就能指定执行自定义方法。但该属性有很多限制,比如其方法必须和接口在同一个类中等。

@GetMapping("testSlowCall")
@SentinelResource(value = "testSlowCall", fallback = "testSlowCallFallback")
public String testSlowCall() throws InterruptedException {
    // select db
    TimeUnit.SECONDS.sleep(3);
    return "ok";
}

public String testSlowCallFallback() {
    //降级
    return "fallBack";
}

(4)熔断策略之异常比例和异常数

这里的异常指业务异常,不包括Sentinel的流控异常BlockedException。

 

一.异常比例

下面为了测试异常比例的熔断策略创建一个接口,这个接口的资源名为testErrorRate,降级方法为testErrorRateFallback。

@GetMapping("testErrorRate")
@SentinelResource(value = "testErrorRate", fallback = "testErrorRateFallback")
public String testErrorRate(Integer id) {
    if (null == id) {
        throw new NullPointerException("id is null");
    }
    return "ok";
}

public String testErrorRateFallback(Integer id) {
    //降级
    return "fallBack";
}

这个接口的熔断规则如下:当10秒(统计时长)内达到10个请求(最小请求数)以上,而且请求异常比例超过20%时,就会触发熔断并熔断时长为5秒。熔断5秒后资源testErrorRate会变成Half Open状态。即5秒后的第一个请求如果没有问题则恢复正常,否则就继续熔断。

二.异常数

异常数就是在单位时间内超出错误数则触发熔断,和异常比例唯一不同的就是异常比例是计算百分比,而异常数是直接计算错误数量。

(5)总结

一.熔断策略总结

策略一:慢调用比例

衡量在一定时间内,响应时间超过阈值的调用占总调用数量的比例。比如在一分钟内,有10%的调用响应时间超过1秒。

 

策略二:异常比例

衡量在一定时间内,发生异常的调用占总调用数量的比例。比如在一小时内,有5%的调用发生异常。

 

策略三:异常数

计算在一定时间内发生的异常调用的绝对数量。例如,过去一天中,发生了100次调用异常。

 

二.实际应用场景总结

一个在线支付系统有一个接口用于处理支付请求:

 

场景一:慢调用比例

过去10分钟内有20%的支付请求的响应时间超过了3秒,超过预设的阈值。

 

场景二:异常比例

在过去一小时内,有2%的支付请求发生了异常,可能是由于网络问题或支付平台故障引起的。

 

场景三:异常数

昨天共有30次支付请求发生了异常,可能是由于无效的订单号或者连接超时导致的。

 

6.热点规则使用演示

(1)参数限流的意思

(2)参数限流的实战

 

(1)参数限流的意思

传统的流量控制,一般是通过资源维度来限制某接口或方法的调用频率。但有时需要更细粒度地控制不同参数条件下的访问速率,即参数限流。

 

参数限流允许根据不同的参数条件设置不同的流量控制规则,这种方式非常适合处理特定条件下的请求,能更加精细地管理流量。

 

场景一:假设有一个在线电影订票系统,某个接口允许用户查询电影的放映时间。但只希望每个用户每10秒只能查询接口1次,以避免过多的查询请求。这时如果直接将接口的QPS限制为5是不能满足要求的。因为需求是每个用户每5分钟只能查询1次,而不是每秒一共只能查询5次。

 

因此可以使用参数限流设置一个规则,根据用户ID来限制每个用户的查询频率。将限流的维度从资源维度细化到参数维度,从而实现每个用户每10秒只能查询接口1次。

 

场景二:一个SAAS服务/中台服务,希望能根据不同的商家/业务方来做限流规则。比如规模大的商家/业务方,允许调用的QPS是1000,而小的只能是50。

 

(2)参数限流的实战

下面实现每个用户每10秒只能查询一次电影票信息,首先在pom.xml添加依赖:

<!-- 可以使用热点参数限流功能 -->

    com.alibaba.csp
    sentinel-parameter-flow-control
    1.8.6

然后新增一个接口:

@RestController
@RequestMapping("/hotKey")
public class TestHotKeyController {
    @GetMapping("/testMovieTicket")
    @SentinelResource(value = "testMovieTicket", fallback = "testMovieTicketFallback")
    public String testMovieTicket(String userId, Integer movieId) {
        return "testMovieTicketSuccess";
    }

    public String testMovieTicketFallback(String userId, Integer movieId) {
        return "testMovieTicketFail";
    }
}

接着针对该接口配置如下规则:相同参数值(第一个参数)每隔10秒只能请求一次。

新增热点规则之后,就可以对热点规则进行编辑。在编辑框里,提供了高级选项进行进一步的选择。

假如希望影院工作人员可以每秒查询10次,老板可以每秒查询100次,而购票者则只能每10秒查询一次。其中工作人员的userId值为100和200,老板的userId值为9999。那么可以如下配置:注意限流阈值是以秒为单位的,需要乘以统计窗口时长10。

(3)总结

参数限流允许基于不同参数条件来限制不同请求的访问速率。在实际应用中,参数限流可以适用于各种场景。例如秒杀系统、订票系统、广告点击等。通过合理设置参数限流规则,可以有效地保护系统免受过多请求的影响。

 

7.授权规则使用演示

(1)授权规则的核心概念

(2)授权规则的实战

 

(1)授权规则的核心概念

有时只允许特定用户或IP地址才能访问系统,这时可以使用Sentinel的授权规则(黑白名单)功能。授权规则功能有两个核心概念:黑名单和白名单。

 

一.黑名单

一种限制性授权规则,用于限制某些用户、操作或资源的访问权限。

 

二.白名单

一种授予性授权规则,允许特定用户、操作或资源访问受限制的功能。

 

授权规则适用的场景:

 

场景一:用户身份认证

当用户登录系统时,系统会验证其身份,确保用户是合法用户。例如,只有登录的管理员才能发布新的电影信息。

 

场景二:角色和权限分配

系统会为不同角色的用户分配不同的权限。例如,管理员可管理电影信息,编辑可编辑但不能发布,访客只能浏览。

 

场景三:操作访问控制

某些操作可能只能被特定角色的用户执行。例如,只有管理员可以删除电影信息。

 

场景四:数据保护

系统需要保护敏感数据,确保只有授权的用户可以访问。例如,用户只能访问自己的个人信息。

 

场景五:安全访问

限制只有特定用户或特定IP地址可以访问系统,防止恶意用户或恶意IP地址对系统进行攻击或滥用资源。

 

(2)授权规则的实战

首先需要定义授权规则,Sentinel授权规则配置类是AuthorityRule。因此自己定义一个类,初始化Sentinel授权规则配置,代码如下:

 

这里没有借助Sentinel Dashboard来配置规则,而是通过代码方式实现。配置规则并不一定要借助Sentinel Dashboard,通过代码也可以完成。如下代码就设置了一个白名单策略,且白名单的值只能是user1或user2。这意味着只有user1和user2这两个用户才能访问"authority-demo"资源。

@Component
public class SentinelAuthorityRule {
    @PostConstruct
    public void init() {
        doInit();
    }
    
    private void doInit() {
        //定义资源名称
        String resource = "authority-demo";
        //定义授权规则,此类为 Sentinel 内部类,并非自己定义的
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(resource);
        //白名单
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        //限制user1/user2能访问
        rule.setLimitApp("user1,user2");
        //注册授权规则
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    }
}

当然,对应于Sentinel Dashboard中进行授权规则配置如下:

接着添加接口应用授权规则:

@RestController
@RequestMapping("/sentinelAuthority")
public class SentinelAuthorityController {
    //资源名称
    private static final String RESOURCE_NAME = "authority-demo";

    //userId此处当参数传递仅仅是为了模拟,实际生产环境中还需符合自身公司规范,比如放到header里,从header获取等
    @GetMapping("/demo")
    public String demo(String userId) {
        //进行授权规则验证
        ContextUtil.enter(RESOURCE_NAME, userId);
        Entry entry = null;
        try {
            entry = SphU.entry(RESOURCE_NAME);
            //执行业务逻辑
            return "ok";
        } catch (BlockException ex) {
            //授权验证未通过
            //处理授权验证失败的逻辑
            return "fail";
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
}

最后启动服务进行验证便可发现:

http://localhost:19966/sentinelAuthority/demo?userId=user1返回ok;
http://localhost:19966/sentinelAuthority/demo?userId=user2返回ok;
http://localhost:19966/sentinelAuthority/demo?userId=user3返回fail;

 

8.系统规则使用演示

(1)什么是系统规则

(2)系统规则实战

 

(1)什么是系统规则

系统规则是针对整个系统进行流量控制的,是操作系统级别或服务器级别的,不是应用级别或资源级别的。一台服务器可以部署很多应用(资源),虽然可为每个资源设置流控规则,但是服务器也可能被压爆。如果因为一个服务导致服务器垮了,那么也会对其他服务产生影响。所以,服务器本身也需要可靠性,也需要做一些流控规则配置。比如入口QPS阈值指的是当前服务器上所有接口的入口流量。

 

它提供多种阈值类型,当触发这些阈值时,系统便会拒绝新的流量请求。

一.Load(负载)阈值

Load阈值可以限制系统的负载。当系统负载过高时,限制新的请求进入系统,以避免系统崩溃。

 

应用场景: 电商平台在大促活动期间,大量用户涌入平台使得系统资源紧张。此时可以使用设置Load阈值,当系统负载过高时,限制新请求进入系统。

 

二.RT(平均响应时间)阈值

RT阈值可限制系统的平均响应时间,即请求从接收到响应的平均耗时,RT高可能表示系统负载或性能存在问题。

 

应用场景:在一个即时消息应用中,确保用户能及时收到消息非常重要。此时可以设置RT阈值,限制消息接口的平均响应时间,保障用户体验。

 

三.线程数阈值

线程数阈值可限制系统的并发线程数,避免过多线程竞争资源影响性能。

 

应用场景:在一个高并发的在线游戏中,每个用户都可能占用一个独立线程。此时可以设置线程数阈值,限制并发线程数,避免过多的线程占用资源。

 

四.入口QPS(每秒查询数)阈值

入口QPS阈值用于限制所有接口的入口流量,防止短时间内大量请求涌入。

 

应用场景: 在一个热门的抢购活动中,用户可能频繁刷新页面以获取商品信息。可以使用入口QPS阈值,限制商品详情接口的访问频率。

 

五.CPU使用率阈值

CPU使用率阈值用于限制系统的CPU使用率,避免CPU负载过高。

 

应用场景:在一个图像渲染应用中,每个任务需要大量计算资源。可以设置CPU使用率规则,限制渲染任务的CPU使用率。

 

(2)系统规则实战

如下是官网的Demo:通过系统规则管理类SystemRuleManager加载initSystemRule()的阈值。一旦超出initSystemRule()中配置的阈值,新进来的请求将被直接拒绝。

package com.alibaba.csp.sentinel.demo.system;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;

public class SystemGuardDemo {
    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();
    
    private static volatile boolean stop = false;
    private static final int threadCount = 100;
    private static int seconds = 60 + 40;
    
    public static void main(String[] args) throws Exception {
        //打印测试结果
        tick();
        //初始化系统规则配置
        initSystemRule();
        
        //启动多线程进行测试
        for (int i = 0; i < threadCount xss=removed xss=removed xss=removed xss=removed> rules = new ArrayList();
        SystemRule rule = new SystemRule();
        //max load is 3,系统最高负载为3.0
        rule.setHighestSystemLoad(3.0);
        //max cpu usage is 60%,系统CPU最大使用率为60%
        rule.setHighestCpuUsage(0.6);
        //max avg rt of all request is 10 ms,系统最大平均响应时间为10毫秒
        rule.setAvgRt(10);
        //max total qps is 20,系统最大QPS为20
        rule.setQps(20);
        //max parallel working thread is 10,系统最大并行线程数为10
        rule.setMaxThread(10);
        
        rules.add(rule);
        //通过系统规则配置管理类SystemRuleManager将规则配置注册进去,一旦超出上述阈值,新进来的请求将被直接拒绝
        SystemRuleManager.loadRules(Collections.singletonList(rule));
    }
    
    private static void tick() {
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
    }
    
    static class TimerTask implements Runnable {
        @Override
        public void run() {
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    
                }
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;
                
                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;
                
                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;
                System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal + ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
                if (seconds-- <= 0) {
                    stop = true;
                }
            }
            System.exit(0);
        }
    }
}

 

9.集群流控使用演示

(1)部署集群环境

(2)集群流控实战

 

(1)部署集群环境

Sentinel源码中就有一个实现了集群流控的Demo。

因此为了演示集群效果,可以直接启动:

com.alibaba.csp.sentinel.demo.cluster.app.ClusterDemoApplication;

接下来会启动三次此项目,分别指定不同的端口。启动之前,需要在IDEA中分别添加如下JVM参数。

 

第一次启动项目时添加的参数:

 -Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded 
 -Dserver.port=8081 -Dcsp.sentinel.dashboard.server=localhost:8080 
 -Dcsp.sentinel.api.port=8881

对应的截图如下:

第二次启动项目时添加的参数:

 -Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded 
 -Dserver.port=8082 -Dcsp.sentinel.dashboard.server=localhost:8080 
 -Dcsp.sentinel.api.port=8882

对应的截图如下:

第三次启动项目时添加的参数:

 -Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded 
 -Dserver.port=8083 -Dcsp.sentinel.dashboard.server=localhost:8080 
 -Dcsp.sentinel.api.port=8883

对应的截图如下:

分别启动三个ClusterDemoApplication项目,然后再分别访问如下地址:

http://localhost:8081/hello/sentinel
http://localhost:8082/hello/sentinel
http://localhost:8083/hello/sentinel

接着打开Sentinel Dashboard机器列表,便会发现注册进来了三个服务。

(2)集群流控实战

首先,需要新增Token Server和Token Client。可以随意选择一个服务作为Token Server,另外两个作为Token Client。

接着,新建一个集群规则:集群QPS阈值为1。这也就意味着三台服务加起来的QPS为1,即整个集群内1s只能访问一次。配置如下图所示:

至此,就完成了集群限流的配置。

 

From:https://www.cnblogs.com/mjunz/p/18825935
东阳马生架构
100+评论
captcha