Go 中的速率限制:请求速率限制完整指南
速率限制是现代 Web 应用程序和微服务中一种至关重要的负载管理和保护机制。在 Go (Golang) 语言中,有众多实现速率限制的方法和库,从简单到高级。在本文中,我们将解析核心概念、流行的库,并展示代码示例。
什么是速率限制,为什么需要它?
速率限制是一种控制客户端在特定时间段内可以发送请求数量的技术。主要目标:
- 防御 DDoS 攻击 — 防止服务器过载
- 公平分配资源 — 确保所有用户平等访问
- 节约资源 — 降低基础设施成本
- 防止滥用 — 防御爬虫和暴力破解
主要的速率限制算法
有几种经典算法,各有其优势:
- 令牌桶 — 最流行的算法,“令牌”以特定速率累积
- 漏桶 — 请求以固定速率处理,超额部分被丢弃
- 固定窗口 — 在固定时间间隔内简单的请求计数器
- 滑动窗口 — 比固定窗口更精确,考虑时间边界
Go 中流行的速率限制库
1. 标准库:golang.org/x/time/rate
这是 Go 团队的官方扩展,实现了令牌桶算法。它轻量级、易于使用,非常适合大多数场景。
package main
import ( "fmt" "net/http" "time" "golang.org/x/time/rate")
func main() { // 创建限制器:每秒 2 个请求,突发容量为 5 limiter := rate.NewLimiter(2, 5)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if !limiter.Allow() { http.Error(w, "请求过多", http.StatusTooManyRequests) return } fmt.Fprintf(w, "OK: %s", time.Now().Format(time.RFC3339)) })
http.ListenAndServe(":8080", nil)}2. github.com/ulule/limiter
一个更灵活的库,支持多种存储后端(Redis、Memcached、内存)和算法。适用于分布式系统。
import ( "github.com/gin-gonic/gin" "github.com/ulule/limiter/v3" "github.com/ulule/limiter/v3/drivers/store/memory")
func main() { // 配置:每秒 10 个请求 rate := limiter.Rate{ Period: 1 * time.Second, Limit: 10, }
store := memory.NewStore() instance := limiter.New(store, rate)
r := gin.Default() r.Use(func(c *gin.Context) { key := c.ClientIP() context, err := instance.Get(c.Request.Context(), key) if err != nil { c.AbortWithStatusJSON(500, gin.H{"error": "内部错误"}) return } if context.Reached { c.AbortWithStatusJSON(429, gin.H{"error": "请求过多"}) return } c.Next() })
r.Run(":8080")}3. github.com/juju/ratelimit
来自 Canonical 的简单可靠的库,基于令牌桶算法。API 极简。
import ( "github.com/juju/ratelimit" "time")
func main() { // 创建 bucket:100 个令牌,每秒补充 10 个令牌 bucket :=