首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >新来的外包,限流算法用的这么6

新来的外包,限流算法用的这么6

作者头像
有态度的马甲
发布2025-11-24 14:23:48
发布2025-11-24 14:23:48
750
举报
文章被收录于专栏:精益码农精益码农

CloudFlare介绍限速[1]的文章, 讲述了限速的使用场景和运作方式。

最难的是构建一个既高效又匹配需求的算法。

1.流行的限速器[2]

① 固定窗口限速 Fixed Window Counter

跟踪固定时间间隔(如 1 分钟)内的请求数量。一旦达到上限,就会拒绝该窗口中的后续所有请求。

UserCase: 可预测流量、低精度需求的简单API,比如云平台会对开发者提供 “免费调用API”的限速额度。

eg: 公共天气 API 允许每个用户每分钟 100 次请求,任何额外请求都会返回 “429 请求过多 ”响应。

Drawback:客户端可通过在两个时间窗口的边界堆砌请求(例如,在1min时间窗口的第59秒和下一个1min窗口的第1s都堆砌100 个请求), 轻松突破qps=100/min 语义。

固定窗口算法对应最字面意义的qps语义,但是qps漏洞也很明显(很容器在瞬间被突破)。

② 滑动窗口限速 Sliding Window Log

维护每个请求的时间戳日志,并根据滚动时间窗口计算限制。

UserCase:要求高精度的核心系统,如金融交易 API 或欺诈检测机制。

eg: 银行 API 限制每小时取款次数为 10 次,每次新请求都要根据最近1小时的取款次数来评估。

Drawback: 当扩展到数百万用户或频繁请求时,内存使用量大(可以想象对每一个请求都会产生一个kv窗口计数器,会有一个很大的map),计算成本高。

滑动窗口算法对应严格意义的qps语义,从任意一个请求点切入的统计都试图保持恒定的qps。

那为什么会有漏桶和令牌桶算法?

上面的固定窗口和滑动窗口算法,他们都聚焦在“维持qps”, 对于超出qps的流量他们会直接拒绝。

漏桶算法和令牌桶不仅聚焦“维持qps”, 同时不完全无脑拒绝:

在突发流量时,能给出等待处理/有暂存令牌迅速处理的行为, 也就是能应对突发的流量波动。


③ 漏桶限速 Leaky Bucket

想象一个底部有小孔的水桶,请求(水)被添加到桶中,并以稳定的 “漏水 ”速度进行处理,从而防止突然的洪水泛滥。

UserCase: 是平滑流量的理想选择,例如在流媒体服务或支付处理中,可预测的输出是至关重要的。

eg: 视频流平台对其内容交付网络的 API 调用进行管理,确保一致的播放质量。

Drawback: 不适合处理突发事件,如闪电销售或促销活动。

漏洞算法基于“稳定的漏水机制”,也维持了严格意义的qps语义,但是他有桶,短时的波动流量可凭借桶容量排队依次漏出, 超过桶容量的请求还是会被拒绝。

物理学意义(压强/高度因素、动态平衡)不能维持”稳定的漏水机制“, 这里的稳定漏水机制是需要技术强制实现

④ 令牌桶限速[3]

令牌以固定速率生成并存储在一个桶中。每次请求都会消耗一个令牌(令牌产生快于实际请求,桶满多余令牌会被丢弃);

支持短时间瞬发(只要有令牌)。

UserCase: 适合需要处理偶尔出现的流量高峰,同时执行总体限制(如登录尝试或搜索查询)的应用程序接口。

eg: 某电子商务网站在结账时允许每秒最多 20 个请求的突发流量,但将总体流量限制在每分钟 100 个请求(r= 1.6, b=20)。

Drawback: 需要固定速率补充令牌,技术上稍复杂。

令牌桶通过稳定的投放令牌,也尝试维持了恒定的qps语义,严格上讲令牌桶维持恒定的qps不是依靠稳定的投放令牌, 而是消耗令牌。

消耗令牌的速率某些时刻可能就不是恒定的:在突发大流量时,桶中暂存的令牌可以迅速给到请求用(这一瞬间突破qps语义),而不用像漏桶一样排队等待被处理(因漏水塑形)。

漏桶算法和令牌桶的区别

漏桶算法聚焦于”流量塑形“,有一定量的突发流量对应能力,但不多;

令牌桶算法大部分情况下会产生”流量塑形“的效果,优势是:应对突发流量。

举个例子🌰: 容量均为20的漏桶和令牌桶, 分别以10/s的速率漏水、投放令牌。

日常流量恰好稳定是10/s,某瞬间突发流量: 来了100个请求。

请求迅速堆满漏桶:后80个请求被拒绝,前20个请求被处理(第一个请求迅速被处理,第20个在第2s末被处理完,because恒定的漏水塑形)。

而令牌桶在这一瞬间,因为桶中有暂存令牌,可迅速给到请求使用,在这一瞬间能突破10/s 的qps(第1s放行30个请求,第2s依靠投递令牌放行10个请求,只要请求不自己取消,这突发的流量最后都会被消化掉), 因此令牌桶才成为互联网应对突发流量的优质限速算法。


2. 今日快闪:基于gin框架的原生api限速器。

golang内置了一款限速器golang/x/time/rate[4], 基于令牌桶限速算法

维基百科令牌桶限速器[5]Think in this way, someone put 1 candy per second(r) in your bucket, then you can eat only 1 candy per sec. If your bucket can hold 10(b) candies and if you haven't eaten any of them for a while, your bucket will be full then you can eat 10 candies as fast as you can eat at a time.

将该限速器应用到gin框架上:

代码语言:javascript
复制
package main

import (

    "github.com/gin-gonic/gin"

    "golang.org/x/time/rate"
)

func RateLimiter() gin.HandlerFunc {
    limiter := rate.NewLimiter(10, 30)
    return func(c *gin.Context) {

        if limiter.Allow() {
            c.Next()
        } else {
            c.JSON(http.StatusTooManyRequests, gin.H{
                "message": "Limite exceed",
            })
        }

    }

func NewLimiter(r Limit, b int) *Limiter 限速器控制事件发生的频率。 它实现了一个大小为 b 的 “令牌桶”,最初是满的,并以每秒 r 个令牌的速度重新装满。Limiter对多个goroutine同时使用是安全的。

Limiter主要有三个方法,AllowReserveWait,大多数时候开发者应该使用Wait

这三种方法都消耗一个令牌,当没有可用令牌时,它们的行为有所不同。

  • 如果没有可用的令牌,Allow 将返回 false。
  • 如果没有可用的令牌,Reserve 将返回未来令牌的预留以及调用者在使用它之前必须等待的时间。
  • 如果没有可用的令牌,则 Wait 会阻塞,直到可以获得令牌或其关联的 context.Context 被取消。

方法AllowN、ReserveN 和WaitN 消耗n 个令牌。

2.1 使用http基准测试工具wrk[6]压测

wrk -t12 -c400 -d30s http://localhost:8080/themes/2运行基准测试30 秒,使用12个线程,并保持400个HTTP连接打开。

① 不加限速中间件:

在此压力下,宏观的qps:250

② 将RateLimiter应用到可能被刷单的API

r.GET("/themes/:id", RateLimiter(), func(c *gin.Context) { ...... })

在r=10,b=30的令牌桶设定下,大部分请求都被迅速拒绝了,显得qps很大。


最后介绍一个企业级的ulule/limiter限速器[7]

  • Simple API
  • "Store" approach for backend
  • Redis support (but not tied too)
  • Middlewares: HTTP, FastHTTP and Gin

参考资料

[1]

CloudFlare介绍限速: https://www.cloudflare.com/zh-cn/learning/bots/what-is-rate-limiting/

[2]

流行的限速器: https://medium.com/redis-with-raphael-de-lio/rate-limiting-with-redis-an-essential-guide-df798b1c63db

[3]

令牌桶限速器: https://medium.com/@mojimich2015/token-bucket-algorithm-rate-limiting-explained-with-python-go-73a9f192fda3

[4]

golang/x/time/rate: https://github.com/golang/time/blob/master/rate/rate.go

[5]

令牌桶限速器: https://en.wikipedia.org/wiki/Token_bucket

[6]

http基准测试工具wrk: https://github.com/wg/wrk

[7]

ulule/limiter: https://github.com/ulule/limiter/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-11-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 精益码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.流行的限速器[2]
  • ① 固定窗口限速 Fixed Window Counter
  • ② 滑动窗口限速 Sliding Window Log
  • 那为什么会有漏桶和令牌桶算法?
  • ③ 漏桶限速 Leaky Bucket
  • ④ 令牌桶限速[3]
  • 漏桶算法和令牌桶的区别
  • 2. 今日快闪:基于gin框架的原生api限速器。
  • 2.1 使用http基准测试工具wrk[6]压测
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档