Java 如何做接口限流
我们在点外卖时,会不会遇到“今日订单太火爆,请稍后再试”的提示?刷短视频时,偶尔也会碰到“访问人数过多,请稍后”的弹窗——这些都是系统在“限流”,避免短时间内太多请求挤垮服务器。接口限流就是给系统设一道“安全阀”,防止流量过载,而Java作为常用的后端开发语言,实现接口限流有几种接地气的方法。
第一种:简单粗暴的计数器法
这是最容易理解的方式,就像小区门禁的“刷卡次数限制”。假设我们给某个外卖下单接口设了“每秒最多10个请求”的规则:用Java写代码时,定义一个变量记录当前1秒内的请求数,每来一个请求就加1,当超过10个时,直接返回“太火爆,请稍后”。

举个生活化的例子:小区单元门的门禁,保安数着每分钟进的人数,到了10个就拦住后面的人,等下一分钟再放行。这种方法的好处是代码写起来简单,适合小流量的个人项目,但缺点很明显——如果刚好在1秒的边界,前1毫秒来10个,后1毫秒又来10个,总共20个请求,系统还是会“崩”,这就是俗称的“计数器漏洞”。
第二种:更平滑的滑动窗口法
为了弥补计数器的漏洞,我们可以把1秒分成多个小格子,比如分成10个100毫秒的小窗口。每来一个请求,就记录它所在的小窗口,统计最近10个小窗口(也就是1秒内)的总请求数。还是用小区门禁的例子:把1分钟分成6个10秒的小格子,当前第5个10秒的格子里有5人,第6个有5人,总共有10人,就拦住后面的人。这种方法不会出现边界处的流量突增,限流效果更平滑,适合中小流量的业务。
用Java实现的话,我们可以用一个数组存每个小窗口的请求数,每过100毫秒滚动一次窗口,减去最老的那个窗口的数值,再加上新窗口的请求数,就能得到当前1秒内的总请求数。
第三种:专业工具兜底的令牌桶法
如果是像外卖平台那样的大流量,靠自己写代码算就太麻烦了,这时候可以用现成的工具,比如Guava库里的RateLimiter,它用的是“令牌桶”思路。就像奶茶店的取号机,每隔固定时间就往桶里放一定数量的“令牌”,顾客要喝奶茶得先拿令牌,拿不到就不能点单。
在Java里用RateLimiter的代码很简单,比如给下单接口设“每秒最多10个请求”,就创建一个RateLimiter实例,参数填10。每当请求来的时候,调用acquire()方法,如果能拿到令牌就处理请求,拿不到就拒绝。这种方法的好处是能精准控制请求的“发放速度”,不会让流量忽高忽低,而且不用自己处理复杂的算法,适合高并发的生产场景。
最后要注意的小细节
不管用哪种方法,有个关键点不能忘:限流是“保护系统”,不是“拒绝用户”。如果用户被拦住了,最好给个提示,比如“您的请求已排队,预计等待3秒”,而不是直接冷冰冰地拒绝。另外,限流的规则也要灵活调整,比如节假日外卖单多,就把每秒请求数调高,工作日再调低,根据实际业务情况来。
其实Java做接口限流,本质就是给系统装个“调节阀”,根据流量大小控制开关,让系统既不被挤垮,又不会浪费资源。