什么是自适应限流?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 限流体系认知:面试官不仅仅是想知道你会不会调 Sentinel 的 API,更是想看你能否说清楚传统限流(计数器、漏桶、令牌桶)的局限性,以及自适应限流到底 “自适应” 在哪。

  2. 系统观察能力:是否理解用 CPU、RT、负载这些运行时指标来刻画系统健康度,而不是拍脑袋给个 QPS 阈值。

  3. 原理深度:知不知道 BBR、利特尔法则(Little's Law)、Netflix Concurrency Limits 这些底层算法和工业实现,而不是停在概念层。

核心答案

自适应限流(Adaptive Rate Limiting)指的是:不预先设定固定的限流阈值,而是根据系统实时的运行指标(响应时间、CPU 负载、并发数等),动态调整通过的流量大小,让系统始终跑在 “最大吞吐 + 稳定” 的临界点上。

一句话对比:

类型 阈值来源 典型算法 问题
传统限流 提前配置(人工压测估算) 计数器、滑动窗口、漏桶、令牌桶 阈值定高了打挂系统,定低了浪费资源
自适应限流 实时指标驱动 BBR、Netflix 并发限制、Sentinel 自适应 实现复杂,需要可靠的指标采集

我自己的体会是,传统限流像 “给路口装个红绿灯,每分钟固定放 100 辆车”,自适应限流像 “智能信号灯,看堵不堵再决定放多少”。前者简单粗暴,后者聪明但难做。

自适应限流机制
自适应限流机制

深度解析

一、为什么传统限流不够用?

传统限流最大的痛点就一句话:阈值难定

  • 压测估出来的阈值不准:测试环境和线上环境硬件、数据量、依赖服务都不一样,压出来的 QPS 阈值到了线上往往失真。
  • 系统容量是动态的:白天数据库健康能扛 1000 QPS,凌晨备份任务一跑只能扛 300 QPS。固定阈值完全没法适应这种波动。
  • 突发流量应对不了:令牌桶虽然能容许突发,但桶大小还是写死的。

所以在大促、秒杀这类流量剧烈波动的场景,业界就引入了 “自适应” 的思路。

二、自适应限流的核心原理

核心就两个字:反馈

系统实时采集运行指标,根据指标的恶化程度反向调整允许进入的流量。下面这张图能直观看清这个闭环:

自适应限流原理
自适应限流原理

上图这个闭环其实就一句话:请求进来不直接判定,先看系统指标算出当前负载。接近过载就降低并发、丢一部分请求;还有余量就再试着把吞吐往上提。系统就这样一直在临界点附近晃悠,不让自己被打爆,也不让自己闲着。

说白了就是一个 负反馈控制回路(Negative Feedback Loop),跟空调的温度控制一个道理——热了就制冷,冷了就停。

自适应限流反馈闭环
自适应限流反馈闭环

三、几个关键算法和实现

1. 利特尔法则(Little's Law)

自适应限流的数学基础,公式是:

L = λ × W
  • L:系统中同时被处理的请求数(并发数)
  • λ:请求到达速率(QPS)
  • W:每个请求的平均处理时间(RT)

关键推论:如果系统能扛的最大并发是 L_max,那最大 QPS 就是 L_max / W。自适应限流就是动态地去逼近这个 L_max

利特尔法则限流
利特尔法则限流

2. BBR 算法(Google 提出的拥塞控制算法)

BBR 原本用在 TCP 拥塞控制,后来被借鉴到应用层限流。它的核心思想是:

  • 找到最大吞吐量 max_throughtput
  • 找到最小延迟 min_RT
  • 最佳并发数 ≈ max_throughtput × min_RT(也就是带宽延迟积 BDP)

实现逻辑很直接:系统健康的时候就持续试探更高的吞吐;一旦发现 RT 突然飙升(说明队列开始堆积),立马降低并发。

3. Netflix Concurrency Limits

Netflix 开源的一个自适应限流库,提供了几种经典的限流器:

限流器 核心思路
FixedLimit 固定并发限制(基础对照)
VegasLimit 基于 TCP Vegas,根据队列使用情况(实际 RT 与基准 RT 的偏差)调整
Gradient2Limit 基于 RT 梯度(当前 RT 与长期最小 RT 的比值)调整
AIMDLimit 加性增、乘性减(Additive Increase, Multiplicative Decrease)

AIMD 这个思路特别经典:系统正常时缓慢试探增加(每次 +1),一旦过载就立即大幅削减(乘以 0.5),既能逼近上限,又能在过载时快速收缩。

BBR AIMD 自适应限流
BBR AIMD 自适应限流

4. Sentinel 自适应限流

阿里开源的 Sentinel 提供了 SystemRule,可以基于多个维度自适应限流,一共支持 5 个维度:

  • Load AveragehighestSystemLoad):Linux 系统平均负载,按 CPU 核心数配置
  • CPU 使用率highestCpuUsage,默认 > 0.6 触发)
  • 平均 RTavgRt,请求响应时间)
  • 入口 QPSqps
  • 并发线程数maxThread

Sentinel 内部借鉴了 BBR 思路,结合 Java 的 OperatingSystemMXBean 来获取系统指标。注意有个坑:在 Docker 环境下,getSystemLoadAverage() 拿到的是宿主机负载而不是容器内的,所以容器化部署别太依赖 load 指标。

Sentinel 自适应限流
Sentinel 自适应限流

四、代码示例(Sentinel 自适应限流)

import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;

import java.util.ArrayList;
import java.util.List;

public class AdaptiveRateLimitDemo {
    public static void main(String[] args) {
        // 配置系统级自适应限流规则
        List<SystemRule> rules = new ArrayList<>();
        SystemRule rule = new SystemRule();

        // CPU 使用率超过 60% 触发限流
        rule.setHighestCpuUsage(0.6);
        // 平均 RT 超过 10ms 触发限流
        rule.setAvgRt(10);
        // 入口 QPS 超过 5000 触发限流
        rule.setQps(5000);
        // 系统平均负载阈值(Linux 下有效,4 核 CPU 建议设 4.0 左右)
        rule.setHighestSystemLoad(4.0);
        // 入口并发线程数超过 100 触发限流
        rule.setMaxThread(100);

        rules.add(rule);
        SystemRuleManager.loadRules(rules);

        System.out.println("自适应限流规则加载完成");
    }
}

注意几个点:

  • SystemRule系统级 的规则,所有资源共享,不是针对某个具体接口
  • 实际生产里 highestCpuUsage 通常配 0.6~0.8,太低会误杀正常流量
  • Sentinel 还提供 ParamFlowRule(热点参数限流)等更细粒度的规则

五、自适应限流的典型应用场景

不是所有场景都适合自适应限流。简单总结下:

适合自适应限流的场景

  • 接口负载波动大(大促、秒杀、突发热点)
  • 依赖服务 RT 不稳定(第三方接口、数据库慢查询)
  • 微服务网关、API 入口
  • 难以压测出固定阈值的复杂链路

还是用传统限流就够的场景

  • 内部稳定的 CRUD 接口
  • 阈值可以稳定配置的服务
  • 对稳定性要求极致、宁可保守的场景

面试高频追问

  1. 追问一:BBR 算法的核心思想是什么?

找到系统的最大吞吐量和最小延迟,最佳并发数 ≈ 两者乘积(即带宽延迟积 BDP)。健康时探测增加,过载时快速收缩。

  1. 追问二:自适应限流会误杀正常流量怎么办?

通常配合 预热(warmup)和 冷却时间(cool-down)来避免抖动。指标采集要做平滑处理(滑动平均、指数加权),不能被瞬时尖刺带偏。

  1. 追问三:Sentinel 和 Hystrix 在限流上有什么区别?

Hystrix 主要是熔断降级,限流能力弱;Sentinel 是限流 + 熔断 + 系统自适应三位一体,且支持热点参数限流和实时监控。

常见面试变体

  • “为什么令牌桶不能解决大促场景的限流问题?”
  • “Sentinel 的 SystemRule 是怎么实现的?”
  • “如何动态调整限流阈值?”
  • “BBR 算法在 Java 中如何实现?”

记忆口诀

自适应限流三要素:实时指标(RT、CPU、并发) + 动态阈值(不写死) + 反馈控制(升则加,过则砍)。

一句话记法:传统限流定死阈值,自适应限流让系统自己找上限——靠的是 Little's Law(L = λ × W)这个数学基础,加上 BBR 那套 “探测 + 收缩” 的反馈回路。

总结

一句话:自适应限流就是让系统根据实时运行状态自己调整通过流量,解决的是传统限流 “阈值难定、应对不了波动” 的痛点。数学基础是利特尔法则,工业实现看 Google BBR、Netflix Concurrency Limits 和阿里 Sentinel。生产环境真正落地时,往往是传统限流 + 自适应限流组合使用,前者保底,后者扛波动。