Spring Cloud Alibaba快速入门-Sentinel流量控制(FlowRule)
文章目录
- 什么是流量控制(Flow Control)?
- 新增流控规则
- 流控模式
- 直接策略(默认模式)
- 链路策略
- 触发逻辑
- 场景
- 特点
- 示例
- 关联策略
- 触发逻辑
- 场景
- 特点
- 示例
- 流控效果
- 快速失败
- 核心思想
- 适用场景
- 特点
- 示例
- Warm Up(预热 / 冷启动)
- 核心思想
- 适用场景
- 特点
- 示例
- 排队等待(Rate Limiting / Queueing)
- 核心思想
- 适用场景
- 示例
什么是流量控制(Flow Control)?
核心思想:流量控制是 Sentinel 的“刹车系统”。它的原理是监控应用流量的 QPS(每秒查询率)或并发线程数等指标,当达到指定的阈值时,就采取预定的控制行为(如直接拒绝、排队等待等),以保证系统不会被突发流量冲垮,从而保障服务的高可用性。
简单来说,其目的就是 “避免让系统处理能力之外的需求涌入系统”。
新增流控规则
进入Sentinel页面,点击
- 资源名:需要控制的资源名称
- 针对来源:一般为default,表示无论从任何地方来的请求
- 阈值类型:
- QPS:统计每秒请求数,一般设置QPS
- 并发线程数:统计并发线程数,统计线程池
- 单机阈值:每秒数
单机均摊:当均摊阈值为1时,集群中每一个机器每秒最多执行一次
总体阈值:当均摊阈值为1时,整个集群每秒最多执行一次
流控模式
在 Sentinel的流控模式中,直接、关联、链路是三种核心的流控模式,它们的核心区别在于触发流量控制的条件和场景不同。
- 调用关系包括调用方、被调用方;
- 一个方法又可能会调用其它方法,形成一个调用链路的层次关系;
- 有了调用链路的统计信息,我们可以衍生出多种流量控制手段。
直接策略(默认模式)
- 触发逻辑:当当前资源自身的流量达到阈值时,直接对当前资源的请求进行限流。
- 场景:最常用的模式,用于保护单个资源不被过度访问。
- 特点:
- 只关注当前资源的流量,与其他资源无关;
- 配置简单,适用于绝大多数基础限流场景。
链路策略
触发逻辑
当从指定入口资源过来的请求访问当前资源时,若流量达到阈值,对该链路的请求进行限流(其他入口的请求不受影响)。(即:只限制 “特定调用链” 上的流量,允许其他链路正常访问当前资源)
场景
- 用于精细化控制 “同一资源在不同调用链路下的流量”,避免某一条链路的异常流量影响其他链路。如:
- 同一个Service方法被多个Controller调用。例如,UserService.getUserById() 方法既被 AdminController 调用,也被 AppController 调用。
- 希望只限制来自 AdminController 这个调用链路的流量,而不影响 AppController 的正常用户访问。
特点
- 限流范围限定在 “特定入口→当前资源” 的调用链路上;
- 需通过如@SentinelResource注解明确标记资源和入口(或通过配置指定上下文),实现链路识别。
示例
@GetMapping("/create")
public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId") Long productId) {return orderService.createOrder(userId, productId);
}@GetMapping("/seckill")
public Order seckill(@RequestParam(value = "userId" ) Long userId,@RequestParam(value = "productId") Long productId){Order order = orderService.createOrder(productId, userId);order.setId(Long.MAX_VALUE);return order;
}
配置文件添加web-context-unify: false
spring:cloud:sentinel:transport:# 指定Sentinel控制台地址dashboard: localhost:8080# 设置为true,表示启动时立即初始化Sentinel。eager: true# 关闭Web上下文统一(sentinel_spring_web_context)web-context-unify: falsefeign:sentinel:enabled: true
如果web-context-unify使用默认true,则会显示
点击/seckill下的createOrder
注意:启动Sentinel后需要执行一次代码才会显示
设置入口资源只对/seckill限制
访问两个接口时即可发现只有/seckill接口被限制
http://127.0.0.1:8081/create?userId=10&productId=11
http://127.0.0.1:8081/seckill?userId=10&productId=11
关联策略
触发逻辑
- 当与当前资源相关联的另一个资源的流量达到阈值时,对当前资源的请求进行限流。(即:B 资源流量过高时,限制 A 资源的请求,防止 A 资源进一步加剧 B 的压力)
场景
用于保护 “有依赖关系的资源”,避免因关联资源过载而引发连锁反应。如:
- 数据库读写分离:当大量的写操作(关联资源A)达到阈值,可能拖慢数据库时,就限制读操作(资源B)的流量,保证写操作能正常完成。
- 支付与查询:当支付接口(关联资源A)流量激增时,为了保证支付核心流程,可以适当限制订单查询接口(资源B)的流量。
特点
- 限流的是 “当前资源”,但触发条件是 “关联资源” 的流量超标;
- 适用于需要 “牺牲非核心资源保护核心资源” 的场景(如写操作通常比读操作更核心)。
示例
新增两个接口模拟读写分离场景
@GetMapping("/writeDb")
public String writeDb(){System.out.println("writeDb");return "writeDb success....";
}@GetMapping("/readDb")
public String readDb(){System.out.println("readDb");return "readDb success....";
}
先快速调用多次http://127.0.0.1:8081/writeDb
在调用http://127.0.0.1:8081/readDb
出现以下情况
注意:这里只有在调用writeDb接口超过阈值时,才会触发readDb接口的限制。只调用readDb接口不会触发
流控效果
流控效果是流量控制的 “执行动作”,当某个资源的流量达到预设阈值(如 QPS=100)时,Sentinel 会根据配置的流控效果对超额请求进行处理。其核心目标是:在保护系统不被过载的同时,最大化资源利用率,或保证请求处理的公平性。
注意:只有快速失败支持流控模式(直接、关联、链路)的设置
快速失败
核心思想
流量一旦达到阈值,立即拒绝后续所有请求。并抛出异常,不进行任何等待或缓冲。
适用场景
- 对响应时间敏感的业务(如支付接口、核心交易链路),快速失败避免请求堆积,防止雪崩
- 非核心业务,优先保证系统稳定性,牺牲部分请求可用性。
特点
- 优点:处理速度快,对系统资源消耗低(无需维护队列或计时);
- 缺点:可能导致短时间内大量请求失败,用户体验较差(如 “瞬间报错”)。
示例
设置规则
在代码中设置状态码为429,用于处理Sentinel限流或降级时的异常
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.qf.common.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;import java.io.PrintWriter;/*** 用于处理Sentinel限流或降级时的异常*/
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response,String resourceName, BlockException e) throws Exception {response.setStatus(429); //too many requestsresponse.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();R error = R.error(500, resourceName + " 被Sentinel限制了,原因:" + e.getClass());String json = objectMapper.writeValueAsString(error);writer.write(json);writer.flush();writer.close();}
}
使用apipost进行压测
断言状态码为200成功
设置10个线程,发送5秒
这里可以看到成功请求数为11个
总结:快速失败会把多余的请求直接抛弃。
Warm Up(预热 / 冷启动)
核心思想
让系统从“冷”状态平滑地过渡到“全速”状态(热身),避免冷启动时瞬间高并发导致系统崩溃。
适用场景
- 系统刚启动(或重启)后,需要时间加载缓存、初始化连接池等资源(冷系统);
- 流量波动较大的场景(秒杀/抢购系统),避免系统瞬间过载。
特点
- 优点:保护系统不被突发流量冲击,让系统资源(如 CPU、内存)逐步提升负载;
- 缺点:预热期间会有部分请求被限流,需要业务允许 “渐进式可用”。
为什么需要Warm Up?
系统在冷启动(如刚启动、长时间低负载后突然扩容)时,各种资源(如数据库连接池、缓存、JVM JIT编译)可能还未完全准备好。如果瞬间施加全部流量,很可能导致系统因负载过高而崩溃。Warm Up 给它一个“热身”的时间。
示例
效果:一开始只处理三分一的请求(1/10),之后每秒会逐步增加,三秒时和之后每秒处理10个请求
进行压测
查看接口日志
2025-02-25T07:49:36.499+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-4] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:36.500+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-17] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:36.499+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-6] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:37.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-20] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:37.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-18] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:37.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-17] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-2] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-8] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-19] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-11] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-14] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:38.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-18] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-9] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-19] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-20] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-2] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-8] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-1] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-14] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-3] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-16] com.qf.controller.OrderController : ----------readDb----------
2025-02-25T07:49:39.000+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-5] com.qf.controller.OrderController : ----------readDb----------
可以看到每秒访问接口数量在逐步增加,直到每秒10个
排队等待(Rate Limiting / Queueing)
核心思想
当流量超过阈值时,不立即拒绝请求,而是让超限的请求进入队列排队等待,以固定的速率(等于阈值)处理,使用的是漏桶算法的思想。
适用场景
- 需要平滑流量的场景(如秒杀、定时任务触发的批量请求),用排队来缓冲流量,避免恢复瞬间被压垮。
- 对请求延迟不敏感(异步),但要求 “最终处理” 的业务(如日志上报、数据同步)。
示例
当单机阈值设置为2时,表示每隔500ms才允许通过下一个请求。1000ms/2所得。
效果:每秒中处理两个请求,多余的请求进行排队,超过1秒(timeout)丢弃
注意:排队等待不支持流控模式中的关联和链路,配置了也不会起到效果
使用Apipost进行请求发送
2025-02-26T07:33:46.192+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-12] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:46.192+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-5] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:46.192+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-13] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:46.193+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-14] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:46.692+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-10] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:47.192+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-17] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:47.692+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-21] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:48.191+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-13] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:48.691+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-10] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:49.191+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-15] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:49.691+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-12] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:50.197+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-10] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:50.695+08:00 INFO 34312 --- [qf-service-order] [nio-8081-exec-7] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:51.192+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-17] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:51.691+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-13] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:52.191+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-25] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:52.234+08:00 WARN 34312 --- [qf-service-order] [io-8081-exec-25] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to flush: java.io.IOException: Connection reset by peer]
2025-02-26T07:33:52.692+08:00 INFO 34312 --- [qf-service-order] [io-8081-exec-17] com.qf.controller.OrderController : ----------readDb----------
2025-02-26T07:33:52.692+08:00 WARN 34312 --- [qf-service-order] [io-8081-exec-17] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.context.request.async.AsyncRequestNotUsableException: ServletOutputStream failed to flush: java.io.IOException: Connection reset by peer]
开头的情况属于正常,统计时需要有时间起点。开始统计后发现是每秒处理两个请求。
最后有两条WARN级别的日志,表示客户端提前终止了与服务器的连接,导致服务器无法完成响应的发送。新来的请求因为排不上队(集合满了)而被丢弃,导致客户端等待超时后断开连接。