请求限流

简介: 本文介绍如何使用Sentinel实现接口限流与降级,通过配置QPS阈值保护商品查询接口,并结合JMeter进行压测验证。同时讲解了线程隔离机制,包括信号量隔离的应用,确保系统在高并发下的稳定性。

1.3.1 配置限流策略

下边我们对item-service的商品查询接口进行限流,找到商品查询的簇点链路,点击"流控"

在弹出的菜单中填写QPS单机阈值为5,表示每秒最多处理5个请求

AI:什么是QPS

QPS 是 "Queries Per Second" 的缩写,中文通常称为“每秒查询率”或“每秒请求数”。它是一个衡量系统性能的重要指标,特别是在评估 Web 服务器、数据库系统、API 接口等的负载能力时经常使用。

QPS 表示系统在一秒钟内能够处理的查询或请求的数量。这个指标可以帮助开发者和运维人员了解系统的处理能力和性能瓶颈。例如,如果一个 Web 服务的 QPS 为 100,则意味着该服务在一秒钟内最多可以处理 100 个请求。

你的主打项目必须要提前准备好:QPS、TPS、RT、下载量、日活、最大数据量的表是什么

1.3.2 限流测试

首先去掉item-service服务中查询商品信息接口的休眠代码。然后启动item服务

下边我们用jmeter压力测试工具进行压力测试:Jmeter快速入门

JMeter 是一个广泛使用的开源性能测试工具,主要用于测试 Web 应用程序的负载和性能。它是由 Apache Software Foundation 开发和维护的,完全用 Java 编写,因此可以在任何支持 Java 的平台上运行。

找到课程资料中的JMeter安装包apache-jmeter-5.4.1.zip,解压到非中文的目录,进入bin下双击打开jmeter.bat

打开软件切换到中文

接下来找到课程资料下的“雪崩测试.jmx” 拖到JMeter面板中

最终效果如下(如有不同,及时修改)

设置模拟线程数等参数:

表示:总共发送1000个请求,用100秒发送,循环次数是1即执行10秒结束。

根据设置参数可知,每秒发送10个秒在100秒可完成1000个请求。

在“HTTP请求”界面设置压力测试请求的地址:确保跟你本地端口一致

右键“限流测试”点击“启动”

测试结果可以在“汇总报告”中查看,每次请求的次数在“察看结果树”中查看。

从吞吐量可以看出每秒发送10个请求,异常数是0

通过sentinel的实时监控界面可以看出对商品查询接口的请求,通过的QPS为5,拒绝QPS为5。

因为上边我们配置了对商品查询接口限流QPS为5,所以每秒10个请求查询/carts,远程调用商品查询服务接口的QPS只有5,说明被限流了。

注意:如果实时监控图无法正常显示需要进入虚拟机进行时间同步。

ntpdate ntp1.aliyun.com
如果无法执行上边的命令需要下载ntpdate
yum install ntpdate -y

此时,需要耐心等待一下后重试,就可以看到有结果了:通过只有5。

如果你还是没有,也可以调整Jmeter参数,把1000,100改成:100,10,循环次数:永远

再查看每次的请求和响应数据发现,由于编写了商品查询接口远程调用的降级逻辑,当商品查询接口被限流后将会走降级方法,从jmeter测试结果可以看到被限流的请求无法获取商品信息

再查看cart-service的控制台,在降级方法中捕获到了 com.alibaba.csp.sentinel.slots.block.flow.FlowException 异常,这说明接口被限流后sentinel客户端会抛出FlowException 异常。

查看Jmeter也可以看到大量拒绝信息

1.3.3 小节

sentinel限流怎么实现?

我们项目使用Sentinel实现限流控制。

  1. 首先在服务提供方配置sentinel,引入sentinel的依赖,配置sentinel的地址
  2. 通过Sentinel控制台配置限流策略,可以配置QPS阈值、并发线程数等。
  3. 当方法被限流会走直接拒绝。

1.4. sentinel降级

上面讲的是A--Feign/Dubbo->B服务时候,对B的做熔断、限流,可如果我只想对A本身做限流怎么实现?

1.4.1 问题描述

下边我们对/carts接口进行限流测试,找到GET/carts簇点

点击“流控” 设置QPS 单机阈值为6

截止目前,我们一共设置了两个流控规则

用jmeter测试,通过sentinel进行实时监控,通过QPS为6,拒绝QPS为4,符合我们的预期结果

当/carts接口被限流时我们访问此接口(需要在Jmeter压测期间测试),需要连续多点击几次

结果内容:Blocked by Sentinel (flow limiting),从字面内容看是被sentinel限流。

为什么访问item-service的商品查询接口走了降级方法,而访问/carts没有走降级方法呢?

1.4.2 sentinel实现降级

这里我们需要重新梳理下:

前边cart-service远程调用item-service服务的商品查询接口正常走降级方法,这是因为我们编写了ItemClient接口的降级类ItemClientFallbackFactory,并且我们在cart-service服务中集成了sentinel,在cart-service的application.yml配置文件中配置了feign使用sentinel,如下:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

也就说,在cart-service通过openfeign远程调用item-service时通过sentinel进行降级,最终执行ItemClientFallbackFactory类中指定的降级方法。这里我们是对/carts进行限流,并没有针对此接口编写降级方法

AI:sentinel实现降级

针对feign远程调用我们通过实现FallbackFactory接口去编写远程调用接口对应的降级逻辑,而针对非feign远程调用的降级逻辑我们需要使用@SentinelResource注解去实现

首先使用 @SentinelResource  定义资源,编写降级方法

@ApiOperation("查询购物车列表")
@SentinelResource(value = "queryMyCarts", fallback = "queryMyCartsFallback", blockHandler = "queryMyCartsBlockHandler")
@GetMapping
public List<CartVO> queryMyCarts(){
    return cartService.queryMyCarts();
}
//当发生非限流非熔断异常走此方法
public List<CartVO>  queryMyCartsFallback(Throwable throwable){
log.error("非限流、非熔断异常执行的降级方法,throwable:",  throwable);
return new ArrayList<>();
}
//当发生熔断、限流走此方法
public List<CartVO>  queryMyCartsBlockHandler( BlockException blockException){
log.error("触发限流、熔断时执行的降级方法,blockException:",  blockException);
return new ArrayList<>();
}

然后在sentinel中设置资源的流控

删除针对/carts设置的流控规则

再次使用jmeter进行压力测试

观察cart-service控制台,当/carts限流后正常执行降级方法,日志如下:

18:37:31:767 ERROR 4696 --- [nio-8082-exec-9] c.hmall.cart.controller.CartController   : 触发限流、熔断时执行的降级方法,blockException:

在降级方法中可以返回特殊的信息,或指定特殊的状态码,根据特殊值前端可展示为类似“网络忙请稍后重试” 这样的信息。此时限流期间访问购物车接口,发现就走了降级逻辑,返回空集合:

1.4.3 小节

sentienl降级怎么实现?

对于Feign远程调用对每个远程调用接口实现降级方法,通过实现FallbackFactory接口实现降级方法。

对于非Feign远程调用我们使用@SentinelResource注解编写自定义降级方法。

1.5. 线程隔离

1.5.1 方案介绍

首先我们来看下线程隔离功能,无论是Hystix还是Sentinel都支持线程隔离。不过其实现方式不同。

线程隔离有两种方式实现:

  • 线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果
  • 信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求

如图:

Sentinel的线程隔离就是基于信号量隔离实现的,而Hystix两种都支持,但默认是基于线程池隔离。

1.5.2 Sentinel线程隔离(练习)

下边我们使用Sentinel实现基于信号量的线程隔离。

点击查询商品的FeignClient对应的簇点资源后面的流控按钮:

在弹出的表单中填写下面内容:

注意,这里勾选的是并发线程数限制,也就是说这个查询功能最多使用5个线程,而不是5QPS。如果查询商品的接口每秒处理2个请求,则5个线程的实际QPS在10左右,而超出的请求自然会被拒绝。

cart-service调用商品查询控制在5个线程内,通过线程隔离即使商品服务出现问题也不会影响cart-service服务。

下边修改商品查询接口的代码,添加休眠500毫秒的代码,模拟一次请求需要500毫秒,一秒则可处理2次请求,5个线程可接收10 QPS左右。

将/carts的限流规则调大以免影响商品查询接口的限流控制。

下边使用jmeter进行测试,更改线程数为10000,时间为100秒,每秒需要发送100个请求。

启用测试,通过sentinel实时监控,符合我们的预期。

不知道细心的你是否发现了一个事情:我们设置的Sentinel通过数量,为什么不那么精准呢?

  • 窗口边界:一个请求可能刚好跨越两个窗口,导致单个窗口的统计值略高于设定值。
  • 滑动窗口精度:滑动窗口的划分粒度可能无法完全精确,尤其在请求密集时。
相关文章
|
Java 数据安全/隐私保护 Sentinel
面试官:Sentinel是如何实现限流的?
面试官:Sentinel是如何实现限流的?
1978 1
|
2月前
|
SQL 关系型数据库 数据库
分布式事务
本文介绍了分布式事务的概念、典型场景及解决方案。在微服务架构下,一次业务操作需跨多个数据库和远程调用协作完成,传统本地事务无法保证整体一致性。通过Seata框架可实现分布式事务控制,其AT模式无侵入、高性能,基于两阶段提交与undo log实现最终一致;XA模式则提供强一致性但性能较低。文章还结合下单、支付等场景演示了Seata的集成与应用。
|
2月前
|
存储 负载均衡 算法
负载均衡算法
本文介绍了多种负载均衡算法:随机、轮询、最小活跃数、源地址哈希及一致性哈希。涵盖适用场景、实现原理与代码示例,帮助理解如何高效分配请求,提升系统稳定性与性能。
|
2月前
|
安全 Java 测试技术
从Google线上故障,谈灰度发布的重要性
2025年6月12日,Google Cloud因未灰度发布的新配置引发空指针异常,导致Gmail、YouTube等服务中断超7小时。本文剖析故障根源,详解配置灰度发布的重要性及Nacos等工具的实践方案,强调通过IP、标签、流量等多路径实现安全发布,保障系统稳定性。
 从Google线上故障,谈灰度发布的重要性
|
2月前
|
消息中间件 存储 缓存
RabbitMQ工作模型
工作队列模型通过多个消费者共同消费一个队列中的消息,实现任务的并行处理。默认情况下,消息平均分配给消费者,可能导致处理能力不同的消费者负载不均。通过设置`prefetch=1`,可实现“能者多劳”,即处理速度快的消费者自动接收更多消息,提升整体效率。发布订阅模型则通过交换机(Exchange)将一条消息转发给多个队列,支持Fanout、Direct、Topic等类型交换机,实现广播或多条件路由消息,满足不同业务场景需求。
|
2月前
|
存储 缓存 负载均衡
Nacos注册中心
本文介绍Nacos的安装部署、服务注册与发现、权重控制、集群隔离及临时/持久实例等核心功能,涵盖从环境搭建到高级配置的完整实践,助力微服务架构高效管理。
 Nacos注册中心
|
2月前
|
负载均衡 Java Maven
Eureka服务注册与发现
本文介绍如何搭建Eureka注册中心,实现user-service与order-service的注册,并通过多实例部署模拟负载均衡场景。涵盖工程创建、配置文件编写、服务启动及常见问题解决方案,帮助掌握Spring Cloud服务注册与发现核心机制。
 Eureka服务注册与发现
|
2月前
|
存储 数据库
数据库设计三范式
数据库三范式是设计合理表结构的指导原则:第一范式要求字段原子性、不可再分;第二范式要求消除部分依赖,即主键确定所有非主键;第三范式要求消除传递依赖。但实际应用中应结合项目需求灵活调整,避免过度规范化带来复杂性。
|
6月前
|
人工智能 缓存 监控
大模型性能测试实战指南:从原理到落地的全链路解析
本文系统解析大模型性能测试的核心方法,涵盖流式响应原理、五大关键指标(首Token延迟、吐字率等)及测试策略,提供基于Locust的压测实战方案,并深入性能瓶颈分析与优化技巧。针对多模态新挑战,探讨混合输入测试与资源优化
|
架构师 Devops 测试技术
DevOps 进阶实践课,连续 4 期,看看有你想听的吗?
探索DevOps进阶实践?加入阿里云专家的直播课!了解企业研发规范新思路、云效YAML流水线详解、微服务灰度发布最佳实践和规模化项目管理。资深专家分享实战经验,解答疑问,带你提升DevOps效率。
1405 3