面对CC攻击,如何通过限流算法(令牌桶、漏桶)实现精准控制
摘要:# 面对CC攻击,别硬扛了,试试这两把“流量手术刀” 做网站的朋友,最怕的不是大流量,而是“假流量”——那种每秒几百上千个请求,看着不凶,但专挑你登录、查询、提交这些核心接口打的CC攻击。我见过不少创业团队,业务刚有起色,就被这种“慢性病”拖垮了。服务器…
面对CC攻击,别硬扛了,试试这两把“流量手术刀”
做网站的朋友,最怕的不是大流量,而是“假流量”——那种每秒几百上千个请求,看着不凶,但专挑你登录、查询、提交这些核心接口打的CC攻击。我见过不少创业团队,业务刚有起色,就被这种“慢性病”拖垮了。服务器没宕,但真用户死活进不来,你说冤不冤?
很多人的第一反应是:加钱,上高防!但说实话,不少所谓的高防方案,对付DDoS这种“洪水”还行,面对CC这种“精准点穴”,如果配置不对路,效果真得打个问号。PPT上吹得天花乱坠,真被打的时候,该卡还是卡。
其实,在流量到达你的WAF或者高防IP之前,甚至在你的应用内部,有一道成本更低、更灵活的内功心法——限流算法。今天不聊那些虚的,就聊聊最实用、也最考验功力的两把“流量手术刀”:令牌桶和漏桶。
先泼盆冷水:限流不是银弹,但能让你“死得明白”
在开聊技术之前,得先摆正心态。限流,尤其是自己实现的限流,核心目的不是100%防住攻击(那是高防+WAF+行为分析一套组合拳的事),而是给你的系统上一道“保险丝”。
它的价值在于:
- 避免雪崩:一个接口被CC打挂,不会因为资源耗尽(比如数据库连接池被占满)而拖垮整个服务器。
- 保障核心:哪怕在攻击下,也能确保一部分(比如20%)的真实用户请求能被处理,业务不至于完全停摆。
- 成本可控:相比于盲目扩容或购买昂贵的高防套餐,从代码层面优化,往往是性价比最高的第一道防线。
说白了,它让你从“莫名其妙全瘫”变成“有策略地部分降级”,从被动挨打到有了还手和调整的余地。这种感觉,被CC打过的运维兄弟都懂。
第一把刀:漏桶算法——绝对的“铁面无私”
你可以把漏桶想象成一个底部带有一个固定大小出水口的水桶。不管上方的水(请求)以多快的速度、多大的流量倒进来,从桶底流出的速度永远是恒定的。
它是怎么工作的?
- 请求来了,先尝试“入桶”。
- 如果桶没满,请求就在桶里排队等着被处理。
- 如果桶满了,对不起,后来的请求直接拒绝(返回429 Too Many Requests或者友好的排队提示)。
- 处理端(出水口)严格按照固定的速率(比如每秒10个请求)处理桶里的请求,雷打不动。
活生生的例子: 你有一个短信发送接口,运营商限制你每秒最多发10条。用漏桶算法就太合适了。哪怕突然有1000个恶意请求涌进来要发短信,我的系统也只会不紧不慢地,每秒处理10个。多出来的请求,要么在桶里排队(如果桶足够大),要么直接被丢弃。攻击者想用洪水挤爆我?没门,我的出口就那么大。
它的脾气:
- 优点:输出流量绝对平滑,不会出现任何突发,对下游保护得极好。非常适合需要严格保证处理间隔的场景。
- 缺点:有点“死板”。面对突发的大量正常请求(比如促销活动开始的一瞬间),它也是一视同仁地限速,可能导致用户体验不佳。桶的大小设置也是个学问,设小了容易误伤,设大了又占内存。
我自己的经验是,漏桶特别适合保护那些脆弱的、或者有严格外部限制的下游服务,比如数据库、第三方API、短信/邮件网关。
第二把刀:令牌桶算法——“通情达理”的守卫
令牌桶就更像是一个有人情味的保安。它手里有一桶“令牌”,以固定的速率往桶里添加。每个请求过来,必须拿到一个令牌才能被放行处理。如果桶里有令牌,立刻取走一个,请求被处理;如果桶里暂时没令牌了,请求可以选择等待(排队)或者被拒绝。
和漏桶的核心区别在哪? 关键在于桶里的令牌可以累积!如果一段时间没有请求,令牌会慢慢攒起来。当突然一波正常流量过来时,系统可以一次性消耗掉积累的令牌,快速处理这些突发请求,之后再恢复到匀速状态。
再举个栗子: 你网站的文章详情页,平时每秒就几十个请求。突然有一篇爆文上了热搜,一秒内来了5000个真实用户点击。如果用令牌桶(假设每秒生成100个令牌,桶最大容量1000个),那么系统可以立刻拿出积攒的令牌,快速处理掉这波突发请求中的一部分,让大部分用户能秒开文章。虽然最终会回到限速状态,但至少抓住了流量高峰,用户体验好得多。
它的脾气:
- 优点:允许一定程度的突发流量,更贴合真实的业务场景,用户体验更好。这是它比漏桶更受欢迎的主要原因。
- 缺点:配置相对复杂。你需要决定:令牌产生的速率(长期平均处理能力)、桶的容量(允许的突发量)。这两个值配不好,要么防不住攻击,要么误伤正常用户。
说白了,令牌桶在“防护”和“体验”之间做了个聪明的折中。它明白,全部一刀切是不行的。
怎么选?我的实战“土办法”
别记理论了,直接上我的选择思路:
-
看场景,看下游:
- 如果要保护一个恒定能力的后端(比如物理设备、有严格QPS限制的付费API),用漏桶。给它一个稳定的工作节奏,它才能长寿。
- 如果要保护自己的应用业务,希望既防攻击又不错过正常流量高峰,用令牌桶。大部分Web API网关(像Nginx、Spring Cloud Gateway)的限流默认就是令牌桶算法,不是没道理的。
-
看需求,看体验:
- 追求绝对平滑和确定性 -> 漏桶。
- 追求应对突发和更好体验 -> 令牌桶。
-
别单干,组合拳: 在实际的高防架构里,限流算法从来不是孤军奋战。它通常是这么用的:
- 最外层(高防IP/WAF):基于IP、会话的粗粒度频率限制和挑战(如验证码)。
- 中间层(网关/负载均衡):基于令牌桶的全局或API维度限流,这是主力。
- 最内层(应用代码):针对关键业务逻辑(如登录、下单)的细粒度漏桶或令牌桶限流,甚至结合用户ID、设备指纹。
最后说句大实话: 算法是死的,参数是活的。令牌桶的速率和容量设多少?这玩意儿没有标准答案。我的土方法是:先看业务平时峰值的1.5到2倍作为基准,然后故意模拟攻击测试一下,观察监控数据(CPU、响应时间、错误率)和业务日志,边调边看。不上线实测的限流配置,都是纸上谈兵。
限流算法就像给你的系统装上了调节阀和保险丝,它不能让你刀枪不入,但能让你在CC攻击的“泥石流”中,依然保持清醒,知道哪里在出血,并且有能力保住最重要的业务血脉。
行了,思路就是这些。具体到你的代码里是选用Guava的RateLimiter,还是Redis+Lua自己实现,那就是另一个故事了。先动手把核心接口的保护策略想明白,别等真被打穿了再挠头。

