分布式限流怎么做到全局限流而不仅仅是单机限流
摘要:# 分布式限流:别让单机思维坑了你的全站 前两天跟一个做电商的朋友吃饭,他跟我吐槽:“我们上了限流,后台数据看着挺美,结果大促一来,整个支付网关还是挂了。你说怪不怪?” 我听完就笑了:“你是不是只做了单机限流?” 他愣了一下:“对啊,每台机器都限了,…
分布式限流:别让单机思维坑了你的全站
前两天跟一个做电商的朋友吃饭,他跟我吐槽:“我们上了限流,后台数据看着挺美,结果大促一来,整个支付网关还是挂了。你说怪不怪?”
我听完就笑了:“你是不是只做了单机限流?”
他愣了一下:“对啊,每台机器都限了,还不够?”
这就是典型的“单机思维陷阱”。 你以为给每台服务器都装了个“水龙头”,流量就能控制住了。结果呢?攻击者或者突发流量,根本不会跟你讲规矩——它们会同时拧开你所有的水龙头。单台机器是没超载,但你的数据库、下游服务、共享资源,直接被冲垮了。
说白了,单机限流就像给家里的每个房间单独装了电表,但总闸还是那个老闸。每个房间用电都没超标,结果一开空调,总闸“啪”一声跳了——全家黑灯瞎火。
单机限流的“死穴”:看不见全局
我自己看过不少架构,问题往往不是没上限流,而是配错了。
单机限流(比如用Guava的RateLimiter,或者Nginx的limit_req模块)在本地玩玩还行。它只管自己这一亩三分地,根本不知道隔壁兄弟正在经历什么。
举个例子: 你有10台应用服务器,每台单机限流设置是1000 QPS。理想情况下,总容量是1万 QPS,对吧?
但现实是:
- 流量不均:可能因为负载均衡策略、热点数据、甚至机房网络抖动,导致其中3台机器扛了6000的请求,另外7台闲得发慌。那3台早就触发了限流,疯狂拒绝请求,而整体流量其实还远没到1万。
- 资源竞争:就算每台机器请求数均匀,它们最终都要访问同一个数据库、同一个缓存集群、同一个第三方接口。你单机限流1000,10台机器同时打向数据库,那就是1万 QPS——数据库可能撑死就3000。结果就是,应用服务器觉得自己挺守规矩,数据库却被活活打死。
- 状态不同步:A机器刚刚因为一个热点用户触发限流,把人家拒绝了。下一秒,这个用户的请求被负载均衡甩到B机器,B机器一看:“这人我没见过啊,进来吧!” 用户体验就是一会儿能刷出来,一会儿报错,跟抽风似的。
很多所谓的“防护方案”,PPT画得很猛,真遇到不规则流量,瞬间露馅。单机限流,防不住全局的资源瓶颈和糟糕的体验。
那怎么才能“看见全局”?关键就两步
想做到真正的全局限流,你得跳出单机视角,解决两个核心问题:
- 有一个统一的“大脑”知道全局流量计数。
- 所有“手脚”(应用实例)能快速、准确地听从大脑的指挥。
听起来有点抽象?我拿个更生活的例子来说。
这就像一家网红奶茶店开分店。如果每家分店自己决定每天卖多少杯(单机限流),结果可能是:A店在商圈,原料上午就卖光了,后面来的顾客白排队;B店在郊区,原料到晚上还剩一半,浪费了。
全局限流,就是给所有分店配一个中央调度系统。总部实时能看到所有分店的销售总和、库存总和。一旦发现今天全国的草莓快用完了,马上通知所有分店:“草莓系列从现在开始,每家店每小时只能卖20杯!” 所有店同步执行。
在技术世界里,这个“中央调度系统”和“同步机制”,通常靠这几样东西来实现:
1. 找个靠谱的“计数中心”
单机内存计数肯定不行了,你得用一个所有机器都能高速访问的集中式存储来计数。
- Redis:这是最常用的方案,利用它的
INCR命令和过期时间,可以非常方便地做滑动窗口计数。性能好,用起来也简单。 - Sentinel:阿里开源的流量治理组件,它的集群限流模式,底层也是用Redis之类的存储来聚合数据。
- Etcd / ZooKeeper:如果你对一致性强要求更高,可以用它们。不过通常限流场景对绝对一致性要求没那么变态,Redis够用了。
2. 选对“统计算法”
有了计数中心,怎么算也是个学问。别再用简单的计数器法了,那不准。主流的是这两个:
- 滑动窗口算法:把时间切成更细的格子(比如1分钟的限流,切成60个1秒的格子)。计数时,只统计最近60个格子的总和。这比固定窗口精准多了,能避免窗口边界的那两倍流量冲击。
- 令牌桶/漏桶算法:这两个算法经典,能应对突发流量,让流量更平滑。在分布式环境下,就是把桶(令牌数或水位)放在Redis里维护,所有机器都从这个公共桶里取令牌或注水。
3. 处理“脑裂”和延迟
这是最坑的地方。网络总会抖一下,如果因为网络延迟,A机器和B机器从Redis读到的计数差了几毫秒,可能就会做出错误的放行/拦截决定。
- 搞点“预支”或“缓冲”:比如,别等到计数完全达到阈值才拒绝,可以提前一点(比如达到95%)就进入“预警”状态,或者允许短期的小额超支。这能避免因同步延迟导致的误杀。
- 降级策略:一旦发现和“计数中心”失联(比如Redis挂了),立刻降级到单机限流模式。有缺陷的防护,总比裸奔强。 同时赶紧告警,让人工介入。
4. 用现成的“轮子”
别什么都自己造,尤其是创业公司或者业务迭代快的团队。市面上已经有很成熟的网关组件,原生就支持分布式限流:
- Spring Cloud Gateway + Redis:通过自定义过滤器,实现基于Redis的全局速率限制。
- Nginx Plus:商业版的Nginx Plus提供了集群限流功能(
limit_req_zone可以共享状态)。 - 阿里云/腾讯云等云厂商的API网关:这可能是最省心的方式。花钱买服务,它们提供的全局限流功能是开箱即用的,背后是经过大规模实战验证的集群。你自己不用操心Redis集群的部署、扩容和运维。
说点大实话:方案没有最好,只有最合适
看到这里,你可能想找那个“银弹”。但真没有。
- 如果你的业务规模不大,QPS还没过万:先用好Nginx的单机限流,或者Spring Cloud Gateway的简单Redis限流,重点是把数据库等下游资源的保护做好。别过度设计。
- 如果你面临明显的流量不均或热点问题:那分布式限流里的滑动窗口算法是你的首选,它能更精准地控制。
- 如果你追求流量绝对平滑,不允许突发:重点考察漏桶算法的实现。
- 如果你就是怕麻烦,业务不能停:直接上云厂商的API网关。多花点钱,省下的是工程师的头发和半夜的告警电话。这笔账,划算。
最后,记住一个反常识的点:全局限流不是为了把流量堵死,而是为了在关键时刻,保核心、保稳定。 它的配置值,不应该是你系统的理论峰值,而应该是在你下游最脆弱环节(往往是数据库)的承受能力上,再打一个安全余量。
别等到服务器日志里满是“429 Too Many Requests”,用户群里骂声一片的时候,才想起来全局视野这回事。如果你的核心服务还在靠单机限流裸奔,你心里其实已经有答案了,对吧?
行了,就聊这么多。具体代码怎么实现,网上教程一堆,关键是先理清思路。去检查一下你的系统吧。

