实战:电商秒杀系统的多层限流方案

引言:秒杀系统的终极挑战 2024年双11,某电商平台iPhone秒杀: 库存:100台 参与人数:10万人 秒杀时间:10:00:00开始 预期流量:瞬间10万QPS 不做限流的后果: 10:00:00.000 - 10万请求同时到达 ↓ 数据库:100个连接池瞬间耗尽 ↓ 应用服务器:200个线程全部阻塞 ↓ 响应时间:从50ms飙升到30秒 ↓ 系统崩溃:所有接口无法响应 ↓ 用户体验:网站打不开,投诉无数 今天,我们将设计一个完整的秒杀系统限流方案,综合运用前面学到的所有知识。 一、场景分析 1.1 业务需求 秒杀活动: 商品: iPhone 15 Pro Max 库存: 100台 价格: 6999元(原价9999元) 开始时间: 2024-11-11 10:00:00 预计参与人数: 10万人 技术指标: 系统容量: QPS 5000 数据库连接: 100个 应用线程池: 200个 Redis: 10000 QPS 1.2 系统架构 用户(10万) ↓ CDN(静态资源) ↓ ┌─────────────────────────────────┐ │ 第1层:网关限流 │ │ - 总入口QPS:5000 │ │ - 限制单用户频率 │ └────────────┬────────────────────┘ ↓ ┌─────────────────────────────────┐ │ 第2层:接口限流 │ │ - 秒杀接口:QPS 1000 │ │ - Warm Up预热 │ └────────────┬────────────────────┘ ↓ ┌─────────────────────────────────┐ │ 第3层:热点限流 │ │ - 商品维度:每个商品100 QPS │ └────────────┬────────────────────┘ ↓ ┌─────────────────────────────────┐ │ 第4层:库存扣减限流 │ │ - 线程数限流:10个 │ │ - 匀速排队 │ └────────────┬────────────────────┘ ↓ 数据库(100个连接) 二、第1层:网关限流 2.1 网关层的职责 目标: ...

2025-01-21 · maneng

流控策略:直接、关联、链路三种模式

引言:不同的限流粒度 前面我们学习了流控效果(快速失败、Warm Up、匀速排队),解决了"如何处理超出阈值的请求"。 但还有一个问题:限流的目标是谁? 场景思考: 场景1:订单查询接口被限流,应该影响订单创建吗? 场景2:同一个接口,从网关调用和从定时任务调用,限流阈值应该一样吗? 场景3:写接口压力大,是否应该限制读接口来保护写接口? 这些问题的答案,藏在Sentinel的三种流控策略中: 直接:直接限流当前资源 关联:关联资源达到阈值时,限流当前资源 链路:从特定入口调用时才限流 一、直接模式:最常用的限流策略 1.1 原理 直接模式:直接对当前资源进行限流,最简单直接。 资源A:限流阈值100 请求 → 资源A ↓ QPS统计 ↓ 超过100? ├─ Yes → 限流 └─ No → 通过 特点: ✅ 最常用(95%的场景) ✅ 简单直接 ✅ 独立限流,不影响其他资源 1.2 配置方式 FlowRule rule = new FlowRule(); rule.setResource("order_query"); // 资源名称 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS限流 rule.setCount(100); // 阈值100 // 流控策略:直接(默认,可省略) rule.setStrategy(RuleConstant.STRATEGY_DIRECT); FlowRuleManager.loadRules(Collections.singletonList(rule)); 1.3 适用场景 大多数API接口: @RestController public class OrderController { // 订单查询:直接限流 @GetMapping("/api/order/{id}") @SentinelResource("order_query") public Result query(@PathVariable Long id) { Order order = orderService.getById(id); return Result.success(order); } // 订单创建:直接限流 @PostMapping("/api/order/create") @SentinelResource("order_create") public Result create(@RequestBody OrderDTO dto) { Order order = orderService.create(dto); return Result.success(order); } } // 配置规则 FlowRule rule1 = new FlowRule(); rule1.setResource("order_query"); rule1.setCount(1000); // 查询接口1000 QPS FlowRule rule2 = new FlowRule(); rule2.setResource("order_create"); rule2.setCount(500); // 创建接口500 QPS FlowRuleManager.loadRules(Arrays.asList(rule1, rule2)); 二、关联模式:保护关联资源 2.1 原理 关联模式:当关联资源达到阈值时,限流当前资源。 ...

2025-01-21 · maneng

流控效果:快速失败、Warm Up、匀速排队

引言:限流后如何处理请求 前面我们学习了QPS限流和线程数限流,但都是简单的"超过阈值就拒绝"。实际场景中,我们可能需要更灵活的策略: 场景1:系统刚启动,能直接承受高流量吗? 系统冷启动: 缓存为空、连接池未预热、JIT未优化 → 直接放入100 QPS → 系统可能卡死 需要:预热(Warm Up) → 逐步增加流量,给系统预热时间 场景2:突发流量能否平滑处理? 消息队列消费: 瞬间收到1000条消息 → 快速失败:拒绝后面的消息 → 匀速排队:排队等待,平滑处理 Sentinel提供了三种流控效果,满足不同场景需求: 快速失败(默认):超过阈值直接拒绝 Warm Up(预热):逐步增加流量 匀速排队:排队等待,平滑处理 一、快速失败:默认的流控效果 1.1 原理 快速失败是最简单直接的流控效果: 阈值:100 QPS 第1-100个请求:通过 ✅ 第101个请求:拒绝 ❌(立即返回) 第102个请求:拒绝 ❌ ... 下一秒:计数器重置,重新开始 特点: ✅ 简单直接 ✅ 响应快(不等待) ✅ 保护系统(超过阈值立即拒绝) 1.2 配置方式 FlowRule rule = new FlowRule(); rule.setResource("myResource"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); // 流控效果:快速失败(默认,可省略) rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); FlowRuleManager.loadRules(Collections.singletonList(rule)); 1.3 适用场景 场景1:普通API接口 @GetMapping("/api/user/{id}") @SentinelResource(value = "user_query", blockHandler = "handleBlock") public Result getUser(@PathVariable Long id) { User user = userService.getById(id); return Result.success(user); } public Result handleBlock(Long id, BlockException ex) { return Result.fail("系统繁忙,请稍后重试"); } 场景2:秒杀活动 ...

2025-01-21 · maneng

并发线程数限流:防止资源耗尽

引言:QPS限流不能解决所有问题 上一篇我们学习了QPS限流,它是最常用的限流方式。但有些场景下,QPS限流并不够用: 场景:调用第三方支付API // 配置:QPS限流 = 100 @GetMapping("/api/payment/query") public Result queryPayment(@RequestParam String orderId) { Entry entry = SphU.entry("payment_query"); // 调用第三方API(RT=2000ms,非常慢!) PaymentResult result = thirdPartyApi.query(orderId); entry.exit(); return Result.success(result); } 问题分析: QPS = 100 RT = 2000ms(2秒) 需要的线程数 = QPS × RT = 100 × 2 = 200个线程 但Tomcat默认线程池只有200个! 结果: → 200个线程全部被占用 → 其他接口无法响应 → 系统"假死" 核心问题:QPS限流只管数量,不管时间。对于慢接口,即使QPS不高,也可能耗尽线程资源。 今天我们将学习线程数限流,专门应对这类场景。 一、线程数限流的原理 1.1 什么是线程数限流 线程数限流:限制同时处理某个资源的线程数量。 资源:payment_query 线程数限流:最多10个线程 第1-10个请求:线程1-10处理中 第11个请求:被限流(因为已经有10个线程在处理) 第1个请求处理完毕:线程1释放 第11个请求:可以被线程1处理 图示: 请求1 → 线程1 [处理中...2秒] 请求2 → 线程2 [处理中...2秒] ... 请求10 → 线程10 [处理中...2秒] 请求11 → ❌ 被限流(线程池满) 1.2 线程数限流 vs QPS限流 维度 QPS限流 线程数限流 关注点 请求数量 并发数量 计算方式 时间窗口内的请求总数 当前正在处理的请求数 适用场景 快速接口(RT<100ms) 慢速接口(RT>1s) 保护目标 防止流量过大 防止线程耗尽 限流时机 请求到达时 请求到达时 核心区别: ...

2025-01-21 · maneng

QPS限流:保护API的第一道防线

引言:QPS限流是最常用的限流方式 上一篇我们深入理解了限流算法的原理,现在让我们回到实战:如何用Sentinel保护你的API? 答案是:QPS限流(Queries Per Second,每秒查询数)。 为什么QPS限流最常用? 指标对比: QPS(每秒请求数): ✅ 直观易懂 ✅ 与业务指标对应 ✅ 方便压测和监控 并发线程数: ❌ 不直观(多少算多?) ❌ 与业务指标不对应 ❌ 难以设置合理阈值 今天我们将学习:QPS限流的配置方法、阈值设置技巧、压测验证、监控调优等实战内容。 一、QPS的概念与重要性 1.1 什么是QPS QPS(Queries Per Second):每秒查询数/请求数 1秒内收到100个请求 → QPS = 100 1秒内收到1000个请求 → QPS = 1000 QPS与其他指标的关系: QPS = 总请求数 / 时间(秒) 并发数 = QPS × 平均响应时间(秒) 例如:QPS=1000,RT=0.1s → 并发数 = 1000 × 0.1 = 100 吞吐量(TPS): 对于查询接口,TPS ≈ QPS 对于事务接口,1个TPS可能包含多个QPS 1.2 为什么要限制QPS 场景1:保护系统不被打垮 系统极限:QPS = 5000 流量洪峰:QPS = 10000 不限流: → 响应时间从50ms变成5000ms → 线程池耗尽 → 系统崩溃 限流到5000: → 拒绝5000个请求 → 保证5000个请求正常响应(50ms) → 系统稳定 场景2:公平分配资源 ...

2025-01-21 · maneng

限流算法原理:计数器、滑动窗口、令牌桶、漏桶

引言:算法决定限流的精度 前面我们学会了使用Sentinel进行限流,只需要一行配置: rule.setCount(100); // 每秒最多100次 但你有没有想过:Sentinel是如何精确控制每秒100次的? 如果100个请求在1秒的前0.01秒就全部到达,后面0.99秒怎么办? 如果1秒内有120个请求,是拒绝哪20个?前面的?后面的? 如果平时QPS是50,突然来了200的瞬间峰值,能否允许? 这些问题的答案,都隐藏在限流算法中。今天我们将深入理解4种经典限流算法,看看它们各自的特点和适用场景。 一、固定窗口计数器:最简单的限流算法 1.1 算法原理 固定窗口计数器是最直观的限流算法: 时间窗口:每秒钟 限流阈值:100次 秒钟: 0 1 2 3 4 │─────│─────│─────│─────│─────│ 计数: 0→100 0→50 0→120 0→80 0→100 结果: 全通过 全通过 拒20 全通过 全通过 工作流程: 将时间划分为固定窗口(如1秒) 每个窗口维护一个计数器 请求到达时,计数器+1 如果计数器超过阈值,拒绝请求 窗口结束时,计数器归零 1.2 代码实现 public class FixedWindowRateLimiter { private final int limit; // 限流阈值 private final long windowSize; // 窗口大小(毫秒) private AtomicInteger counter; // 当前窗口计数 private long windowStartTime; // 窗口开始时间 public FixedWindowRateLimiter(int limit, long windowSize) { this.limit = limit; this.windowSize = windowSize; this.counter = new AtomicInteger(0); this.windowStartTime = System.currentTimeMillis(); } public synchronized boolean tryAcquire() { long now = System.currentTimeMillis(); // 判断是否需要重置窗口 if (now - windowStartTime >= windowSize) { // 新窗口开始 counter.set(0); windowStartTime = now; } // 判断是否超过限流阈值 if (counter.get() < limit) { counter.incrementAndGet(); return true; // 通过 } else { return false; // 限流 } } } 使用示例: ...

2025-01-21 · maneng

Sentinel Dashboard:可视化流控管理

引言:从命令行到可视化 前面四篇,我们都是通过代码来配置限流规则: FlowRule rule = new FlowRule(); rule.setResource("myResource"); rule.setCount(100); FlowRuleManager.loadRules(Collections.singletonList(rule)); 这种方式虽然灵活,但有三大痛点: 修改麻烦:改阈值需要改代码、重启服务 不直观:看不到实时流量数据 排查困难:出问题时无法快速定位 Sentinel Dashboard解决了这些问题,提供了: ✅ 实时监控:秒级数据刷新,QPS/RT/异常数一目了然 ✅ 规则配置:图形化配置,立即生效 ✅ 机器管理:多实例统一管理 今天我们将学习如何安装和使用Sentinel Dashboard。 一、Dashboard简介 1.1 Dashboard是什么 Sentinel Dashboard是Sentinel的可视化控制台,类似于: Nacos的控制台 Kubernetes的Dashboard Spring Boot Admin 核心功能: ┌────────────────────────────────────────┐ │ 实时监控 │ │ - QPS、RT、异常数 │ │ - 秒级刷新,实时图表 │ ├────────────────────────────────────────┤ │ 规则配置 │ │ - 流控规则、熔断规则、系统规则 │ │ - 图形化配置,立即生效 │ ├────────────────────────────────────────┤ │ 机器管理 │ │ - 机器列表、健康状态 │ │ - 多实例统一管理 │ └────────────────────────────────────────┘ 1.2 Dashboard的架构 ┌───────────────┐ │ 浏览器 │ │ localhost: │ │ 8080 │ └───────┬───────┘ │ HTTP ↓ ┌───────────────────────┐ │ Sentinel Dashboard │ ← 控制台(Java应用) │ 端口: 8080 │ └───────┬───────────────┘ │ 心跳 + 规则推送 ↓ ┌─────────────────────────────────────┐ │ 应用实例1 应用实例2 应用实例3 │ ← 接入的应用 │ port: 8719 port: 8719 port: 8719 │ └─────────────────────────────────────┘ 通信方式: ...

2025-01-21 · maneng

核心概念详解:资源、规则、Context、Entry

引言:为什么要理解核心概念 上一篇我们用20行代码实现了第一个Sentinel程序,是不是很简单? 但如果只停留在"会用"的层面,遇到复杂场景时你会发现: 为什么同一个资源名称,不同地方的限流会互相影响? 如何区分同一个接口的不同调用来源? Entry到底是什么?为什么必须调用exit()? Context有什么用?什么时候需要手动创建? 这些问题的答案,都藏在Sentinel的四大核心概念中:资源(Resource)、规则(Rule)、上下文(Context)、入口(Entry)。 理解了这些概念,你就掌握了Sentinel的"第一性原理",可以灵活应对各种场景。 一、资源(Resource):保护的目标 1.1 什么是资源 资源是Sentinel保护的目标,可以是任何你想保护的东西: 应用层面: ├─ 接口:/api/order/create ├─ 方法:OrderService.createOrder() ├─ 代码块:关键业务逻辑 └─ URL:外部API调用 基础设施层面: ├─ 数据库连接 ├─ Redis连接 ├─ 线程池 └─ 消息队列 核心理念:只要是"有限的、需要保护的东西",都可以定义为资源。 1.2 资源的定义方式 方式1:编程方式(最灵活) Entry entry = null; try { entry = SphU.entry("resourceName"); // 受保护的代码 } catch (BlockException ex) { // 限流处理 } finally { if (entry != null) { entry.exit(); } } 优点: ✅ 灵活,可以保护任意代码块 ✅ 可以传入自定义参数 ✅ 性能最优(没有反射) 缺点: ❌ 代码侵入性强 ❌ 需要手动管理Entry 方式2:注解方式(最简洁) @SentinelResource(value = "getUserById", blockHandler = "handleBlock") public User getUserById(Long id) { return userMapper.selectById(id); } // 限流处理方法 public User handleBlock(Long id, BlockException ex) { return User.getDefault(); } 优点: ...

2025-01-21 · maneng

Sentinel初相识:5分钟快速上手

引言:第一个Sentinel程序 前两篇我们讲了流量控制的本质和微服务的三大挑战,理论已经足够。现在,让我们撸起袖子,动手写第一个Sentinel程序。 目标:用不到20行代码,实现一个每秒只允许1次调用的限流功能。 效果: 第1秒调用:✅ 成功 第2秒调用:✅ 成功 同一秒内第2次调用:❌ 被限流 准备好了吗?让我们开始! 一、Sentinel简介 在动手之前,先简单了解一下Sentinel是什么。 1.1 Sentinel的历史 2012年:阿里内部诞生,应对双11流量洪峰 2018年:开源,贡献给社区 2019年:成为Spring Cloud Alibaba核心组件 2024年:GitHub Star 23k+,生产环境广泛使用 核心数据: 阿里内部:6000+ 应用接入 日请求量:数十亿次 可用性:99.99% 1.2 Sentinel的三大特点 特点1:轻量级 核心库大小:< 1MB 内存占用:< 100MB 性能损耗:< 1ms 特点2:功能全面 流量控制(QPS、并发线程数) 熔断降级(慢调用、异常比例) 系统保护(CPU、Load、RT) 热点防护(参数级限流) 集群流控(分布式限流) 特点3:生态完善 Dashboard控制台 多种规则持久化方案 Spring Boot/Cloud/Dubbo适配器 1.3 Sentinel vs Hystrix 你可能听说过Netflix的Hystrix(已停止维护)。简单对比一下: 维度 Hystrix Sentinel 隔离策略 线程池隔离 信号量隔离(更轻量) 熔断降级 基于异常比例 慢调用、异常比例、异常数 实时监控 简单 丰富(秒级统计) 动态规则 不支持 支持(实时生效) 多维度流控 不支持 支持(QPS、线程数、热点) 社区活跃度 已停更 活跃维护 结论:Sentinel是Hystrix的升级版,功能更强大,性能更好。 ...

2025-01-21 · maneng

微服务时代的三大稳定性挑战

引言:从单体到微服务的演进之痛 2015年,Netflix宣布他们的微服务架构已经包含超过1000个微服务,每天处理数十亿次API调用。这标志着微服务架构从理论走向了大规模生产实践。 但微服务不是银弹。在享受它带来的灵活性、可扩展性的同时,我们也必须面对新的挑战。 上一篇我们讲了流量控制的本质,这篇我们深入微服务场景,看看现代分布式系统面临的三大稳定性威胁:流量洪峰、服务雪崩、资源耗尽。这三个问题如果不妥善处理,任何一个都足以让整个系统在几分钟内瘫痪。 一、挑战1:流量洪峰——当10倍流量来袭 1.1 真实案例:2019年双11零点的惊险时刻 2019年双11,阿里云技术团队事后复盘了一个惊险瞬间: 零点前1秒: 系统QPS:50万/秒 服务器CPU:60% 数据库连接:5000个 零点后1秒: 系统QPS:680万/秒(13.6倍) 服务器CPU:95%(濒临极限) 数据库连接:10000个(已达上限) 零点后2秒: 部分慢查询开始出现 RT从50ms上升到200ms 用户开始疯狂刷新(雪上加霜) 如果没有流量控制和弹性扩容,这个洪峰足以在10秒内压垮整个系统。 1.2 流量洪峰的特征 流量洪峰不是均匀的,而是呈现尖刺特征: QPS | | ╱╲ | ╱ ╲ | ╱ ╲ |─────────────────╱ ╲──────────── | 时间 └─────────────────────────────────────> 平时 活动开始 高峰 回落 关键问题: 短时极高:可能在1秒内达到10倍甚至100倍 难以预测:用户行为受心理因素影响(从众效应) 恢复困难:系统崩溃后,重启需要时间,流量会继续堆积 1.3 微服务架构下的放大效应 单体应用时代,1个用户请求 = 1次数据库查询。 微服务时代: 1个用户请求 → 网关(1次调用) → 订单服务(1次调用) → 用户服务(查询用户信息) → 商品服务(查询商品信息) → 库存服务(检查库存) → 优惠券服务(计算优惠) → 积分服务(计算积分) ↓ 5次下游调用 × 3次数据库查询 = 15次数据库操作 放大效应: ...

2025-01-21 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...