限流到底在限制什么?
聊限流之前,我先问个问题:你的水印接口平时扛多少流量?我见过很多团队,平时一天几千请求,突然搞个活动,几万请求涌过来,服务直接挂了。嗯,这就是典型的「没限流」。说白了,限流就是主动控制流量,不让系统被冲垮。
限流的本质定义
限流,全称「流量限制」(Rate Limiting)。它做的事情很简单:在单位时间内,只允许指定数量的请求通过,超出的请求直接拒绝或排队。 你看,这不是什么高深理论,就是给系统装一个「水龙头」。
我之前接手过一个老旧水印服务,并发处理能力只有 200 QPS。上线后经常半夜被报警吵醒——后来发现是爬虫在批量刷接口。加上限流后,系统稳定多了。说白了,限流不是为了限制用户,而是保护你自己的服务。
两种常见维度:QPS 和并发数
限流到底从哪几个角度看?我个人习惯按两种维度来划分:QPS(每秒请求数) 和 并发数(Concurrency)。很多人傻傻分不清,我画个表讲清楚:
| 维度 | 定义 | 典型场景 | 我的踩坑经验 |
|---|---|---|---|
| QPS | 每秒能处理多少请求 | API 网关、登录接口 | 偶尔突增 10 倍请求,QPS 限流直接拦住 |
| 并发数 | 同时正在处理的请求数 | 数据库连接池、线程池 | 并发数超过 50 时,RT 会飙升到秒级 |
QPS 限流的实际配置
我习惯在代码里用 @RateLimiter 来控制 QPS。以 Java 为例,Sentinel 的规则配置很直观:
// 设置水印接口的 QPS 上限为 500
FlowRule rule = new FlowRule();
rule.setResource("watermark_add");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(500);
FlowRuleManager.loadRules(Collections.singletonList(rule));
注意这里的「count」是每秒允许通过的最大请求数。超过 500 的请求会直接返回降级结果(比如「请稍后重试」)。要是你把 count 设成 5000,而服务器扛不住 5000 QPS……嗯,你猜怎么着?服务照样挂。所以配置前先压测。
并发数限流的典型配置
并发数维度更适合控制线程池或连接池级别的资源。比如你有个文字水印渲染服务,底层用了 20 个线程池线程:
// 限制并发数不超过 20
FlowRule rule = new FlowRule();
rule.setResource("text_watermark_render");
rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
rule.setCount(20);
FlowRuleManager.loadRules(Collections.singletonList(rule));
一旦并发数达到 20,新的请求会排队等待,而不是直接把线程池撑爆。我曾在项目里遇到过并发数配置过高(设了 100),结果线程池耗尽导致线程阻塞,整个服务无法响应其他接口。后来我把并发数压到 30,问题就解决了。
限流与流量整形:不是一回事,但有关系
流量整形(Traffic Shaping)跟限流经常被混淆。我举个例子帮你区分:
- 限流: 堵住多余的水。超出部分直接扔掉或拒绝。
- 流量整形: 把突发的水流变成平滑的涓涓细流。允许等待,但不丢请求。
你想想看,如果水印接口接受 500 QPS,但客户端突然在 1 秒内发了 2000 个请求。限流会直接丢掉 1500 个;而流量整形可能让这 2000 个请求在 4 秒内慢慢处理完,每个请求只延迟几毫秒。哪种更好?
我个人习惯在核心接口上用「令牌桶」做流量整形,既保护系统,又不让用户感到明显的拒绝。看这段伪代码:
// 令牌桶:每 100ms 生成 50 个令牌,桶容量 500
rate = 500; // 每秒 500 个令牌
capacity = 500; // 最大突发 500 个请求
tokens = 500; // 初始满桶
last_refill_time = now();
function try_acquire(count):
refill_tokens()
if tokens >= count:
tokens -= count
return true
else:
return false // 等待下一批令牌
限流维度怎么选?一张图说清楚
为了帮你直观理解 QPS 与并发数的区别,以及限流和流量整形的关系,我画了张结构图:
限流的避坑指南
我自己踩过不少坑,简单列几条最常见的:
- 别把 QPS 和并发数搞混。 我曾经把 QPS 1000 当成并发数 1000,结果线程池直接炸了。你看,两个数字一样,但意义完全不同。
- 限流要配合降级。 光限流不降级,用户看到内部错误会骂人。返回友好的提示(比如“系统繁忙,请稍后”)才是正道。
- 流量整形别设得太松。 我试过桶容量设成平均速率的 5 倍,结果突发流量一来,后端的慢查询直接把数据库拖垮了。建议桶容量不超过平均速率的 1.5~2 倍。
- 分布式环境要共享状态。 单机限流在集群下会失效,必须用 Redis 或 Sentinel 的集群限流模式。
总结本章核心点
限流就是给系统装个刹车,QPS 和并发数是两个不同的刹车踏板。流量整形则是让刹车更平顺的缓冲器。你想想看,如果一个水印接口没限流,就像跑车没刹车——看起来很猛,但早晚要出事。