springcloud二-Sentinel

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • [1. Alibaba Sentinel](#1. Alibaba Sentinel)
    • [1.1 熔断](#1.1 熔断)
    • [1.2 限流](#1.2 限流)
    • [1.3 Sentinel的特性](#1.3 Sentinel的特性)
    • [1.4 Sentinel组成](#1.4 Sentinel组成)
    • [1.5 Sentinel Dashboard下载和部署](#1.5 Sentinel Dashboard下载和部署)
    • [1.6 快速上手](#1.6 快速上手)
    • [1.7 springCloud集成sentinel-修改配置](#1.7 springCloud集成sentinel-修改配置)
    • [1.7 springCloud集成sentinel](#1.7 springCloud集成sentinel)
  • [2. Jemeter](#2. Jemeter)
  • [3. 流量控制](#3. 流量控制)
    • [3.1 配置流控规则](#3.1 配置流控规则)
    • [3.2 基于QPS/并发数的流量控制](#3.2 基于QPS/并发数的流量控制)
    • [3.4 流控效果-warm up](#3.4 流控效果-warm up)
    • [3.5 流控效果-排队等待](#3.5 流控效果-排队等待)
    • [3.6 流控模式-链路](#3.6 流控模式-链路)
    • [3.6 流控模式-关联](#3.6 流控模式-关联)
  • [4. 热点参数限流](#4. 热点参数限流)
  • [5. 限流算法](#5. 限流算法)
    • [5.1 计数器算法](#5.1 计数器算法)
    • [5.2 滑动窗⼝算法](#5.2 滑动窗⼝算法)
    • [5.3 漏桶算法](#5.3 漏桶算法)
    • [5.4 令牌桶算法](#5.4 令牌桶算法)
  • 总结10.56

前言


1. Alibaba Sentinel

在互联⽹应⽤中, 会有很多突发性的⾼并发访问场景, ⽐如618, 双11⼤促, 秒杀等, 这些场景的特点是访问量会突增,远远超出系统所能处理的并发数, 如果系统没有有效的保护机制, 所有流量都进⼊服务器,很可能造成服务器宕机, 从⽽造成巨⼤损失.

为了保证系统的稳定性和可⽤性, 采取⼀定的系统保护策略变得⾄关重要. 其中, 服务限流和服务熔断是两种常⻅的策略

1.1 熔断

服务熔断机制类似于电⼒系统中的保险丝, 当电流超过保险丝的承载能⼒时, 保险丝会熔断以保护电路不受损害. 在分布式系统中, 服务间依赖⾮常常⻅, 当某个服务不可⽤时, 如果没有有效的隔离措施, 故障可能会迅速扩散到整个系统, 导致系统雪崩

处理得太慢了的话,那么所有的线程都在处理,然后就忙死了

F不重要的话,那么f有故障的话,那么就不要去调用f了,隔离f,后面再去调用f,看看f好没好

熔断机制能够在服务故障时及时切断调⽤链, 防⽌故障扩散, 减少对故障服务的资源消耗, 保护系统资源不被耗尽, 从⽽保护系统的整体稳定性和可⽤性

1.2 限流

限流, 就是限制流量的意思

在互联⽹应⽤中, 限流可以确保服务器能够处理的请求数量在合理范围内, 避免因请求过多导致服务响

应慢或失败.可以保证⽤⼾在⾼流量时段仍然能够获得快速响应, 提升⽤⼾体验.

在餐厅中, 如果顾客过多, 服务员可能⽆法及时为每位顾客提供服务, 导致服务质量下降. 限流可以确

保每位顾客都能得到满意的服务

就是限制请求的数量

限流和熔断都是服务保护的策略

熔断是防止故障扩散,因为f慢--》c也慢了--》扩散

限流就是流量太多了就不在接受请求了

熔断是在服务异常的时候触发,熔断直接切断请求,直接不在调用f,返回一个默认值

1.3 Sentinel的特性

Sentinel 是由阿⾥巴巴开源的⼀个⾯向分布式、多语⾔异构化服务架构的流量治理组件. 主要以流量为切⼊点,从流量路由、流量控制、流量整形、熔断降级、系统⾃适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性.

  1. 丰富的应⽤场景
    阿⾥巴巴 10 年双⼗⼀积累的丰富流量场景,包括秒杀、双⼗⼀零点持续洪峰、热点商品探测、预热、消息队列削峰填⾕等多样化的场景
  2. 易于使⽤, 快速接⼊
    简单易⽤, 开源⽣态⼴泛, 针对 Dubbo、Spring Cloud、gRPC、Zuul、Reactor、Quarkus 等框架只需要引⼊适配模块即可快速接⼊.
  3. 多样化的流量控制
    资源粒度、调⽤关系、指标类型、控制效果等多维度的流量控制
  4. 可视化的监控和规则管理
    Sentinel提供了简单易⽤的 Sentinel 控制台, 开发者可以在控制台中看到接⼊的应⽤流量, 以及配置限流规则等

1.4 Sentinel组成

Sentinel分为两个部分

  1. 核⼼库(Java 客⼾端) : 不依赖任何框架/库, 能够运⾏于所有 Java 运⾏时环境, 同时对 Dubbo /
    Spring Cloud 等框架也有较好的⽀持.
  2. 控制台(Dashboard) 基于 Spring Boot 开发, 打包后可以直接运⾏, 不需要额外的 Tomcat 等应⽤容

    核心库直接pom引入就可以了
    Dashboard是一个管理界面,需要下载

1.5 Sentinel Dashboard下载和部署

下载网站

直接下载这个就可以了

启动Sentinel Dashboard

把下载的jar放在⼀个⽬录下, 通过cmd 启动jar

使⽤cmd, 启动命令

java 复制代码
java -jar .\sentinel-dashboard-1.8.8.jar

访问: http://127.0.0.1:8080

默认⽤⼾名和密码都是: sentinel

这个控制台以后是要接入的

我们可以修改账户名和密码的
修改配置sentinel官网

java 复制代码
java -jar -Dserver.port=8100 -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=admin -Dserver.servlet.session.timeout=1440m sentinel-dashboard-1.8.8.jar

这个就是设置端口号8100,账号名和密码为admin,设置过期时间为1440分钟,意思是每次到了这个时间就要重新登录了

这样就成功了

我们用的是cmd,powershell可能会不行

1.6 快速上手

直接创建空的maven项⽬

可以参考官网
快速入门

java 复制代码
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.6</version>
</dependency>

我们这里是对某一个代码块进行限流,这个代码块就是资源

java 复制代码
public static void main(String[] args) {
    // 配置规则.
    initFlowRules();

    while (true) {
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保护的逻辑
            System.out.println("hello world");
	} catch (BlockException ex) {
            // 处理被流控的逻辑
	    System.out.println("blocked!");
	}
    }
}

initFlowRules();是配置流量规则

SphU.entry("HelloWorld")定义了一个资源,这个资源的名称叫做HelloWorld

try (Entry entry = SphU.entry("HelloWorld")) {就是判断流量多不多,如果多的话,就去执行System.out.println("hello world");,不然就去执行 System.out.println("blocked!");

也可以通过我们提供的 注解

java 复制代码
@SentinelResource("HelloWorld")
public void helloWorld() {
    // 资源中的逻辑
    System.out.println("hello world");
}

定义规则

java 复制代码
private static void initFlowRules(){
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    rule.setResource("HelloWorld");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // Set limit QPS to 20.
    rule.setCount(20);
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

HelloWorld就是我们定义资源的名称,这个规则针对哪个资源生效

FLOW_GRADE_QPS是限流的规则,就是每s级别的

setCount指的是20个资源来接收

检查效果

Demo 运行之后,我们可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:

其中 p 代表通过的请求, block 代表被阻止的请求, s 代表成功执行完成的请求个数, e 代表用户自定义的异常, rt 代表平均响应时长。

可以看到,这个程序每秒稳定输出 "hello world" 20 次,和规则中预先设定的阈值是一样的。

直接创建一个maven项目

java 复制代码
public class Main {
    public static void main(String[] args) {
        // 配置规则.
        initFlowRules();

        while (true) {
            // 1.5.0 版本开始可以直接利用 try-with-resources 特性
            try (Entry entry = SphU.entry("HelloWorld")) {
                // 被保护的逻辑
                System.out.println("hello world");
            } catch (BlockException ex) {
                // 处理被流控的逻辑
                System.out.println("blocked!");
            }
        }
    }

    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

这个就是请求超过了20个就会进行限制

sentinel的日志在C:\Users\zjdsx\logs\csp下

以metrics结尾

比如com-ck-Main-metrics.log.2025-09-08.1

控制台现在还关联不到,因为还没有关联起来

java 复制代码
    public static void main(String[] args) {
        // 配置规则.
        initFlowRules();

        for (int i = 0; i < 30; i++) {
            // 1.5.0 版本开始可以直接利用 try-with-resources 特性
            try (Entry entry = SphU.entry("HelloWorld")) {
                // 被保护的逻辑
                System.out.println("hello world"+i);
            } catch (BlockException ex) {
                // 处理被流控的逻辑
                System.out.println("blocked!"+i);
            }
        }
    }

这个到try那里的意思可以这样理解,到了那里之后就直接创建了一个线程,然后这次循环就结束了,就是相当于有一个资源来访问helloword资源了,然后虚拟机很快的,一秒钟肯定能执行三十次循环的,所以相当于一秒钟就有三十个请求,三十个线程了,然后只能处理20个,后面十个只能放弃了

1.7 springCloud集成sentinel-修改配置

我们使用以前的springCloudfeign3项目,然后改个名字,spring-cloud-sentinel-demo2

然后改一下

java 复制代码
    <artifactId>spring-cloud-sentinel-demo2</artifactId>

然后改一下配置

java 复制代码
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: 618c9fc5-87b2-4129-8d7e-37fd867c66f7
java 复制代码
-- 订单服务
-- 建库
create database if not exists cloud_order charset utf8mb4;
use cloud_order;
-- 订单表
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail (
        `id` INT NOT NULL AUTO_INCREMENT COMMENT '订单id',
        `user_id` BIGINT ( 20 ) NOT NULL COMMENT '用户ID',
        `product_id` BIGINT ( 20 ) NULL COMMENT '产品id',
        `num` INT ( 10 ) NULL DEFAULT 0 COMMENT '下单数量',
        `price` BIGINT ( 20 ) NOT NULL COMMENT '实付款',
        `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '订单表';

-- 数据初始化
insert into order_detail (user_id,product_id,num,price)
values
(2001, 1001,1,99), (2002, 1002,1,30), (2001, 1003,1,40),
(2003, 1004,3,58), (2004, 1005,7,85), (2005, 1006,7,94);


-- 产品服务
create database if not exists cloud_product charset utf8mb4;
-- 产品表
use cloud_product;
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail (
        `id` INT NOT NULL AUTO_INCREMENT COMMENT '产品id',
        `product_name` varchar ( 128 ) NULL COMMENT '产品名称',
        `product_price` BIGINT ( 20 ) NOT NULL COMMENT '产品价格',
        `state` TINYINT ( 4 ) NULL DEFAULT 0 COMMENT '产品状态 0-有效 1-下架',
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '产品表';

-- 数据初始化
insert into product_detail (id, product_name,product_price,state)
values
(1001,"T恤", 101, 0), (1002, "短袖",30, 0), (1003, "短裤",44, 0), 
(1004, "卫衣",58, 0), (1005, "马甲",98, 0),(1006,"羽绒服", 101, 0), 
(1007, "冲锋衣",30, 0), (1008, "袜子",44, 0), (1009, "鞋子",58, 0),
(10010, "毛衣",98, 0);

这样就可以启动了


这样就可以了

1.7 springCloud集成sentinel

java 复制代码
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

添加到order-service

然后就是配置到dashboard

java 复制代码
spring:
  cloud:
    sentinel:
     transport:
       dashboard: 127.0.0.1:8100 #sentinel控制台地址
       client-ip: 127.0.0.1 #连接本地Sentinel 可以不配置, 连接服务器Sentinel 需要配置⼀下client-ip

然后我们访问几次order

这样就出现了

簇点链路: 是指在微服务架构中, 请求从进⼊服务到处理完成所经过的完整调⽤链路. 当请求进⼊服务

时, ⾸先会访问DispatcherServlet, 然后进⼊Controller, Service, Mapper, 这样的⼀个调⽤链就叫做簇

点链路

默认情况下, Sentinel starter会为Spring MVC的所有HTTP服务提供限流埋点, 所以如果只想对HTTP服务进⾏限流, 那么只需要添加依赖即可, 不需要修改任何代码. 如果想要对特定的⽅法进⾏限流或者降级, 则可以⾃定义资源来实现

所以这些请求已经就有限流了

但是方法还没有限流

簇点链路这里就可以设置限流了

给这个接口点击流控


然后就可以在流控规则那里看到了

这个意思就是QPS超过1,就会进行限流,QPS指的是一秒的请求数

我们点快一点,就出现了这个限流的响应

但是我们手动来点,使之限流---》手速可能不行--Jmeter

2. Jemeter

Apache JMeter 是 Apache 组织基于 Java 开发的压⼒测试⼯具,⽤于对软件做性能测试

Apache JMeter官⽹下载地址:http://jmeter.apache.org/download_jmeter.cgi

我们早就安装好了

直接点击jemeter.bat就可以使用了

或者命令行的方式

java 复制代码
jmeter

我们已经配置好了的环境变量

直接点击ctrl+s

先添加线程组

这个意思就是相当于5s中之内有50个用户发送请求,然后持续一次

添加http请求

然后我们QPS设置为10

这个就是查看http请求的结果树

我们看到,可以给每个http请求都弄一个结果树,然后也可以给所有http请求弄一个结果树

这样就可以启动了

发现还是拦截了一个的

如果线程数为100呢

这里可以清楚结果树

3. 流量控制

3.1 配置流控规则

3.2 基于QPS/并发数的流量控制

QPS就是每秒的请求数,就是每秒通过的请求数

线程数限流⽤于保护业务线程数不被耗尽.

⽐如A调⽤B, ⽽B服务因为某种原因导致服务不稳定或者响应延迟, 那么对于A服务来说, 它的吞吐量会下降, 也意味着占⽤更多的线程(线程阻塞之后⼀直末释放),极端情况下会造成线程池耗尽. 针对这种问题, 业内有使⽤隔离的⽅案,⽐如通过不同业务逻辑使⽤不同线程池来隔离业务⾃⾝之间的资源争抢(线程池隔离), 或者使⽤信号量来控制同时请求的个数(信号量隔离)。这种隔离⽅案虽然能够控制线程数量, 但⽆法控制请求排队时间. 当请求过多时排队也是⽆益的, 直接拒绝能够迅速降低系统压⼒.如果超出阈值,新的请求会被⽴即拒绝

⽐如银⾏柜台窗⼝, 会按照业务分为不同的窗⼝, 个⼈存取款, 养⽼⾦办理, 企业代发⼯资等. 经常会遇

到⼀种情况就是: 存取款窗⼝排⻓⻰, 但是其他窗⼝却没什么⼈办理

并发线程数就是其他业务慢,并不会影响其他业务慢,一般使用QPS

并发线程数就是同时占用的线程数

3.4 流控效果-warm up

对应对应 FlowRule 中的 controlBehavior 字段.

取值分别为:

• 快速失败( RuleConstant.CONTROL_BEHAVIOR_DEFAULT )=0

• Warm Up( RuleConstant.CONTROL_BEHAVIOR_WARM_UP )=1

• 排队等待( RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER )=2

默认为快速失败

快速失败, 也就是直接拒绝, 对应 RuleConstant.CONTROL_BEHAVIOR_DEFAULT . 该⽅式是默认

的流量控制⽅式,当QPS超过任意规则的阈值后,新的请求就会被⽴即拒绝,拒绝⽅式为抛出

FlowException 。这种⽅式适⽤于对系统处理能⼒确切已知的情况下,⽐如通过压测确定了系统的

准确⽔位.

上⾯的例⼦, 使⽤的就是快速失败.

就是这个响应结果

Warm up, 对应 RuleConstant.CONTROL_BEHAVIOR_WARM_UP . Warm Up 也叫预热模式. 阈值

⼀般是⼀个微服务能承受的最⼤QPS, 但是⼀个服务刚刚启动时, ⼀切资源尚未初始化, 如果直接将QPS跑到最⼤值, 可能导致服务瞬间宕机.

该⽅式主要⽤于系统⻓期处于低⽔位的情况下,当流量突然增加时, 直接把系统拉升到⾼⽔位可能瞬间把系统压垮的, 通过"冷启动",让通过的流量缓慢增加,在⼀定时间内逐渐增加到阈值上限,给冷系统⼀个预热的时间,避免冷系统被压垮的情况

这个预热时长就是一个冷启动的时间

设置流控规则

单机阈值设置为10, Warm Up 模式, 预热时⻓为5s

可以理解为系统在5s后单机阈值逐渐增⻓到10


意思是5s后阈值才是10


发现我们的QPS是逐渐上升的,所以通过的也是越来越多的,就是在5s中,5s后才是正常的阈值10,5s前是慢慢到达阈值10,所以一开始拒绝的请求多,后面没有拒绝了

刚刚启动时, ⼤部分请求失败, 继续往下看, 会发现通过的请求逐渐增多, 最终QPS=10全部通过

请求阈值初始值是 maxThreshold / coldFactor, 持续指定时⻓后, 逐渐提⾼到maxThreshold值,

coldFactor的默认值是3.

如上⾯配置, 设置QPS的maxThreshold为10, 预热时间为5秒, 那么初始阈值就是 10/3 , 也就是3, 然后在5秒后增⻓到10.

maxThreshold 为我们设置的阈值10,coldFactor的默认值是3,所以一开始的阈值就是10/3=3

3.5 流控效果-排队等待

排队等待, 对应 RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER . 这种⽅式严格控制了请

求通过的间隔时间,也即是让请求以均匀的速度通过. 可以理解为让所有请求进⼊⼀个队列中, 然后按照阈值允许的时间间隔依次执⾏. 后⾯的请求必须等待前⾯执⾏完成, 直到超时.

如果QPS为10,那么就每100ms就通过一个请求,意思就是同时发送了10个请求,但是会放在队列里面,100ms通过一个,排队等待着

这种⽅式主要⽤于处理间隔性突发的流量, 例如消息队列.

想象⼀下这样的场景, 在某⼀秒有⼤量的请求到来, ⽽接下来的⼏秒则处于空闲状态, 我们希望系统能够在接下来的空闲期间逐渐处理这些请求, ⽽不是在第⼀秒直接拒绝多余的请求

如果QPS为10,一时突然来了20个请求,那么快速失败的话,一秒钟之内,接受10个请求,然后拒绝10个请求

如果是排队等待的话,会把这20个放在队列里面,每100ms处理一个请求,到达了第二秒的时候,还是会继续处理剩下的十个请求,直到到达超时时间

这个表示一秒钟qps为1,请求超时时间不能超过5s

⽐如阈值为1, 那么每秒执⾏⼀个请求. 超时时间为5s. 现在⼀下⼦来了10个请求, 那么:

第一个请求需要等待时间为0s

第3个请求的 等待时⻓为: 100 * (3-1) = 2000ms

第6个请求的 等待时⻓为: 100 * (6-1) = 5000ms

也就是说, 同⼀时间发起10个请求, 那么会通过6个, 拒绝4个.

那么第七个请求等待时间就会超时,所以会拒绝第7~10个请求

快速失败的话,就会通过一个,拒绝九个



可以看出还是拒绝了4个的

我们添加一个定时器

这个的意思就是,因为线程组的十个请求不一定是同时发送的,可能谁先发,谁后发,这个同步定时器的意思就是,当有10个线程发送的时候,就把这十个一起发送

这个可以先不管

这个是因为太统一发送了,所以一次性就通过了,sentinel根本没有区分出来是几个请求,所以一下子就通过很多了,也有可能会失败,sentinel反应过来有几个请求了

3.6 流控模式-链路

调⽤关系包括调⽤⽅, 被调⽤⽅. ⽅法⼜可能会调⽤其它⽅法, 形成⼀个调⽤链路的层次关系. Sentinel记录资源之间的调⽤链路, 这些资源通过调⽤关系, 相互之间构成⼀棵调⽤树

default表示所有来源

根据调⽤⽅限流

也就是上述流控模式中的: [直接]

这是默认的流量控制⽅式. 当QPS超过任意规则的阈值后, 对当前资源直接限流.

针对来源:

default : 表⽰不区分调⽤者, 来⾃任何调⽤者的请求都将进⾏限流统计. 如果这个资源名的调⽤总和

超过了这条规则定义的阈值,则触发限流.

也就是上述流控模式中的: [链路]

链路限流是指: 统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

为了⽅便演⽰, 我们需要先构建链路

所有的请求接口,sentinel会默认标记为资源

其中order也是一个资源,其他方法,除了有requestMapping的方法,怎么变成资源呢---》用注解

SentinelResource

java 复制代码
    @RequestMapping("/write")//PathVariable就是获取url里面的值
    public String write() {
        orderService.queryOrder();
        return "write";
    }
    @RequestMapping("/read")//PathVariable就是获取url里面的值
    public String read() {
        orderService.queryOrder();
        return "read";
    }
java 复制代码
    @SentinelResource("queryOrder")
    public void queryOrder() {
        System.out.println("查询订单信息");
    }

这样写的话就是两个资源write和read调用了共同的一个资源queryOrder

然后我们去调用一下

发现read下面没有queryOrder这个资源的显示

链路模式中, 是对不同来源的两个链路做监控. 但是sentinel默认会给进⼊SpringMVC的所有请求设置同⼀个root资源sentinel_spring_web_context, 会导致链路模式失效. 我们需要关闭这种对SpringMVC的资源聚合, 修改配置如下:

java 复制代码
    sentinel:
     transport:
       dashboard: 127.0.0.1:8100 #sentinel控制台地址
     web-context-unify: false #关闭context整合

这样就可以了

关闭了整合就变成这样了

现在我们就来针对资源进行限流

意思就是对read进行限制了--》QPS为5

我们发现read有些失败了,

write全部成功了

我们只对read设置了单机阈值为5

---》对queryOrder资源进行限流,它有两个入口,read和write,我们只对read设置了5

所以大概失败了一半,write就没有失败了

3.6 流控模式-关联

当两个资源之间具有资源争抢或者依赖关系的时候, 这两个资源便具有了关联

比如read和write之间就有一个资源的争抢

就有关联

还有就是read依赖于queryOrder这个资源

关联限流就是 统计与当前资源相关的另⼀个资源, 触发阈值时, 对当前资源限流.

⽐如对数据库同⼀个字段的读操作和写操作存在争抢, 读的速度过⾼会影响写的速度, 写的速度过⾼会影响读的速度. 如果放任读写操作争抢资源, 则争抢本⾝带来的开销会降低整体的吞吐量. 可使⽤关联限流来避免具有关联关系的资源之间过度的争抢.

⽐如, /order/wirte 和 /order/read 这两个资源分别代表数据库读写, 我们可以给/order/read 设置限流规则来达到写优先的⽬的, 这样当写库操作过于频繁时, 读数据的请求会被限流.

假设数据库能够承受的qps为1000,就是read和write一起访问的时候,这个资源总共承受的


我们设置一下,就是当写的流量很高的时候,就对读进行限流--》关联

这个意思就是当写的流量超过5的时候,就对读进行限流

先去掉原来的链路限流

发现write正常,read被限流了

,当关联资源write超过5的时候,就会对read限流

在数据库操作中, 读操作和写操作可能会争抢资源(如锁). 通过关联模式, 可以限制读操作的频率, 以

避免对写操作造成过⼤的影响.

• 订单服务可能依赖于库存服务, 如果库存服务的请求量过⼤, 可以通过关联模式限制订单服务的请求

4. 热点参数限流

热点即经常访问的数据.

在上⾯的配置中, 对⼀个接⼝进⾏限流, 所有的请求参数⼀视同仁, 只要达到阈值, 就⼀起限流.

热点参数限流会统计传⼊参数中的热点参数, 并根据配置的限流阈值与模式, 对包含热点参数的资源调⽤进⾏限流. 热点参数限流可以看做是⼀种特殊的流量控制, 仅对包含热点参数的资源调⽤⽣效.

比如id为1,就可以设置阈值为10,id为2,就可以设置阈值为20,

热点参数限流对默认的Spring MVC 资源⽆效, 在资源上需要加 @SentinelResource

java 复制代码
    @SentinelResource("/sentinel/id")
    @RequestMapping("/{orderId}")//PathVariable就是获取url里面的值
    public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId) {
        return orderService.selectOrderById(orderId);
    }

直接给/sentinel/id点击热点

热点资源需要接受参数,参数为1~n个,我们需要设置对第几个参数进行限流

我们这里只有一个参数,所以从0开始,就是第一个参数

对这个参数设置阈值为5

这个意思就是对第一个参数进行限流,如果传的id为1,就是对id=1的参数进行限流,一秒钟之内不能超过5,不然就对id=1进行限流

我们分别定义三个请求,id=1,2,3


发现每个参数的限流都是五个

每秒钟相同参数QPS为5

上述的热点参数配置中, 所有的参数⼀视同仁, QPS都被限定为5, 但是在⼀些场景下, 我们希望可以对某些热点参数进⾏单独限流.

但是在⼀些场景下, 有⼀些热点商品, ⽐如排名⽐较靠前的, 访问次数⽐较多, 我们希望可以对这个热点商品进⾏单独限流, 让他的阈值⾼⼀些或者低⼀些, 就需要使⽤到热点参数限流规则⾥⾯的⾼级选项了.

我们这里写的意思就是id=1,阈值为8,id=2,阈值为15,记得点击添加和保存

发现大概是没有问题的

5. 限流算法

我们学习了使⽤Sentinel完成服务的限流, 要实现服务限流, 最重要的就是限流算法, 下⾯来简单介绍下常⻅的限流实现算法.

5.1 计数器算法

计数器算法, 也叫固定窗⼝限流算法, 这是⼀种⽐较简单的限流实现算法

⾸先维护⼀个计数器, 在指定周期内, 累加访问次数, 当访问次数达到设定的阈值时, 触发限流策略, 当进⼊下⼀个时间周期时, 将访问次数清零. 这个时间周期, 就可以理解为⼀个窗⼝, 计数器记录这个窗⼝接收请求的次数.

如图所⽰: 限定了⼀分钟能够处理的请求数为100, 在第⼀个⼀分钟内, 共请求了60次. 第⼆个⼀分钟,

counter⼜从0开始计数, 在⼀分半钟时,已经达到了最⼤限流的阈值, 这个时候后续的所有请求都会被拒绝

这种算法可以⽤在短信发送的频次限制上, ⽐如限制同⼀个⽤⼾⼀分钟之内触发短信发送的次数

这种算法存在⼀个临界问题, 如图所⽰, 在第⼀分钟的0:58和第⼆分钟的1:02这个时间段内, 分别发出了100个请求, 整体来看就会出现4秒内总的请求量达到200, 超出了设置的每分钟100的阈值--》一瞬间太多了.后面1:02-----2:00都会拒绝请求---》不好

5.2 滑动窗⼝算法

为了解决计数器算法带来的临界问题, 所以引⼊了滑动窗⼝算法. 滑动窗⼝是⼀种流量控制技术, 在TCP⽹络通信协议中, 就采⽤了滑动窗⼝算法来解决⽹络拥塞的情况.

简单来说, 滑动窗⼝算法的原理是在固定窗⼝中分割出多个⼩时间窗⼝, 分别在每个⼩时间窗⼝中记录访问次数,然后根据时间将窗⼝往前滑动并删除过期的⼩时间窗⼝. 最终只需要统计滑动窗⼝范围内的所有⼩时间窗⼝总的计数即可

如图所⽰, 我们将⼀分钟拆分为4个⼩时间窗⼝, 每个⼩时间窗⼝最多能够处理25个请求. 并且通过虚线框表⽰滑动窗⼝的⼤⼩(当前窗⼝的⼤⼩是2, 也就是在这个窗⼝内最多能够处理50个请求). 同时滑动窗⼝会随着时间往前移动, ⽐如前⾯15s结束之后, 窗⼝会滑动到15s~45s这个范围, 然后在新的窗⼝中重新统计数据. 这种⽅式很好地解决了固定窗⼝算法的临界值问题.

Sentinel就是采⽤滑动窗⼝算法来实现限流的

就是在一个窗口中,请求量不要超过这个50

对于上面计数器算法产生问题,我们用一个窗口为4s的来就解决了

滑动窗口的单位就比计数器的单位更小了

5.3 漏桶算法

漏桶算法⾯对限流, 就更加的柔和, 不存在直接的粗暴拒绝. 漏桶限流算法的主要作⽤是控制数据注⼊⽹络的速度, 平滑⽹络上的突发流量.

它的原理很简单, 可以认为就是注⽔漏⽔的过程, 往漏桶中以任意速率流⼊⽔, 以固定的速率流出⽔. 当⽔超过桶的容量时, 会被溢出, 也就是被丢弃. 因为桶容量是不变的, 保证了整体的速率.

就是用一个固定大小漏出来,漏水的速率是一样的

如图所⽰: 在漏桶算法内部同样维护⼀个容器, 这个容器会以恒定速度出⽔, 不管上⾯的⽔流速度多快,漏桶⽔滴的流出速度始终保持不变. 实际上消息中间件就使⽤了漏桶限流的思想, 不管⽣产者的请求量有多⼤, 消息的处理能⼒取决于消费者.

漏桶算法的原理, 也就决定着, 使⽤漏桶算法会有以下缺点:

  1. ⽆法处理突发流量: 漏桶算法以固定的速率处理请求, 当流量突然增加时, ⽆法快速响应和处理这些
    请求. 超出漏桶容量的请求会被丢弃, 这可能导致⽤⼾体验下降.
  2. 可能导致请求延迟: 由于漏桶的流出速率是固定的, 即使在流量较⼩的情况下, 请求也需要排队等待
    处理, 这可能导致请求的响应时间变⻓.
    这些缺点使得漏桶算法在某些需要快速响应或处理突发流量的场景中可能不是最佳选择, 其他限流算法如令牌桶算法可能更适合处理复杂多变的流量场景

5.4 令牌桶算法

令牌桶是⽹络流量整形和速率限制中最常使⽤的⼀种算法. 对于每⼀个请求, 都需要从令牌桶中获得⼀个令牌, 如果没有获得令牌, 则触发限流策略

如图所⽰,系统会以⼀个恒定速度往固定容量的令牌桶中放⼊令牌, 如果此时有客⼾端请求过来, 则需要先从令牌桶中拿到令牌以获得访问资格.

假设令牌⽣成速度是每秒10个, 也就等同于QPS=10, 在请求获取令牌的时候, 会存在三种情况:

  1. 请求速度 > 令牌⽣成速度: 令牌会很快被取完, 后续再进来的请求会被限流.
  2. 请求速度 = 令牌⽣成速度: 流量处于平稳状态.
  3. 请求速度 < 令牌⽣成速度: 说明系统的并发数不⾼, 请求能被正常处理.

由于令牌桶有固定的⼤⼩, 当请求速度⼩于令牌⽣成速度时, 令牌桶会被填满. 所以令牌桶能够处理突发流量. 也就是在短时间内新增的流量系统能够正常处理, 这是令牌桶的特性

长期 请求速度 > 令牌⽣成速度,肯定是会限流的,短期的 请求速度 > 令牌⽣成速度,是可以接受的,因为存着令牌

漏桶限流算法和令牌桶限流算法的实现原理相差不⼤, 最⼤的区别是漏桶⽆法处理短时间内的突发流

量, 漏桶限流算法是⼀种恒定速度的限流算法.

总结10.56

相关推荐
ybq195133454312 小时前
javaEE-Spring IOC&DI
java·spring·java-ee
齐 飞3 小时前
Spring Cloud Alibaba快速入门03-OpenFeign进阶用法
spring boot·后端·spring cloud
椰椰椰耶4 小时前
[Spring Cloud][3]从零开始简单工程搭建实践详解,远程调用
java·数据库·spring cloud
@小匠9 小时前
Spring Cache 多租户缓存隔离解决方案实践
java·spring·缓存
上官浩仁19 小时前
springboot synchronized 本地锁入门与实战
java·spring boot·spring
不会聊天真君64720 小时前
ES(springcloud笔记第五期)
笔记·elasticsearch·spring cloud
草履虫建模1 天前
在 RuoYi 中接入 3D「园区驾驶舱」:Vue2 + Three.js + Nginx
运维·开发语言·javascript·spring boot·nginx·spring cloud·微服务
remaindertime1 天前
(九)Spring Cloud Alibaba 2023.x:微服务接口文档统一管理与聚合
后端·spring cloud·微服务
Barcke1 天前
📘 初识 WebFlux
spring boot·后端·spring