golang简单高效的请求速率限制中间件插件Limiter的使用
Golang简单高效的请求速率限制中间件插件Limiter的使用
Limiter是一个简单高效的Go语言速率限制中间件,具有以下特点:
- 简单易用的API
- 支持"Store"模式的存储后端
- 支持Redis(但不局限于Redis)
- 提供HTTP、FastHTTP和Gin等多种中间件
安装
使用Go Modules安装:
go get github.com/ulule/limiter/v3@v3.11.2
使用示例
以下是使用Limiter的完整示例:
package main
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/ulule/limiter/v3"
"github.com/ulule/limiter/v3/drivers/store/memory"
"github.com/ulule/limiter/v3/drivers/middleware/gin"
)
func main() {
// 1. 定义速率限制规则
// 每小时1000次请求
rate := limiter.Rate{
Period: 1 * time.Hour,
Limit: 1000,
}
// 或者使用简化格式:"<limit>-<period>"
// 支持的周期:
// * "S": 秒
// * "M": 分钟
// * "H": 小时
// * "D": 天
// 例如:"1000-H" 表示每小时1000次请求
rate, err := limiter.NewRateFromFormatted("1000-H")
if err != nil {
panic(err)
}
// 2. 创建存储(Store)
// 这里使用内存存储
store := memory.NewStore()
// 如果是Redis存储,可以这样创建:
// store, err := redis.NewStore(client)
// 3. 创建Limiter实例
limiterInstance := limiter.New(store, rate)
// 4. 创建Gin中间件
middleware := ginlimiter.NewMiddleware(limiterInstance)
// 5. 初始化Gin并应用中间件
router := gin.Default()
router.Use(middleware)
// 示例路由
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello World!")
})
// 启动服务器
router.Run(":8080")
}
工作原理
Limiter的工作原理如下:
- 使用请求的IP地址作为存储中的键
- 如果键不存在,则设置一个默认值并设置过期时间
- 提供两种存储方式:
- Redis: 依赖TTL并在每个请求上递增速率限制
- 内存: 依赖go-cache的分支,使用goroutine清除过期的键
- 当达到限制时,返回429 HTTP状态码
反向代理后使用Limiter
如果你的Limiter在反向代理后面,获取"真实"客户端IP可能会比较困难。Limiter提供了以下解决方案:
-
X-Forwarded-For:
- 不建议直接信任此头部,因为它可以被伪造
- 只有在你的反向代理保证会清除/重写此头部时才能启用
TrustForwardHeader
选项
-
自定义头部:
- 许多CDN和云提供商添加自定义头部来定义客户端IP
- 例如:Fastly的
Fastly-Client-IP
、Cloudflare的CF-Connecting-IP
等 - 可以使用
ClientIPHeader
选项指定这些头部
-
自定义KeyGetter:
- 如果上述方案都不适用,可以使用自定义的
KeyGetter
函数
- 如果上述方案都不适用,可以使用自定义的
为什么选择Limiter
Limiter与其他速率限制包相比有以下优势:
- 简单清晰的API设计
- 灵活的存储后端支持
- 多种框架中间件支持
- 活跃的维护状态
- 完善的文档和示例
Limiter特别适合需要简单高效实现速率限制的场景,尤其适合Gin等Web框架的用户。
更多关于golang简单高效的请求速率限制中间件插件Limiter的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang简单高效的请求速率限制中间件插件Limiter的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang请求速率限制中间件Limiter使用指南
在Go语言中实现请求速率限制是保护API服务免受过载攻击的重要手段。下面我将介绍几种简单高效的速率限制中间件实现方式。
1. 使用golang.org/x/time/rate包
Go标准库中的golang.org/x/time/rate
提供了令牌桶算法的实现,非常适合做速率限制。
package main
import (
"net/http"
"golang.org/x/time/rate"
"time"
)
var limiter = rate.NewLimiter(rate.Every(time.Second), 10) // 每秒10个请求
func limitMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Too many requests", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
limitedMux := limitMiddleware(mux)
http.ListenAndServe(":8080", limitedMux)
}
2. 使用github.com/ulule/limiter/v3
ulule/limiter是一个功能更丰富的第三方限流库,支持多种存储后端。
package main
import (
"net/http"
"github.com/ulule/limiter/v3"
"github.com/ulule/limiter/v3/drivers/middleware/stdlib"
"github.com/ulule/limiter/v3/drivers/store/memory"
)
func main() {
// 定义限流规则: 10 requests per minute
rate := limiter.Rate{
Period: 1 * time.Minute,
Limit: 10,
}
store := memory.NewStore()
instance := limiter.New(store, rate)
middleware := stdlib.NewMiddleware(instance)
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
http.ListenAndServe(":8080", middleware.Handler(mux))
}
3. 基于IP的速率限制
更实用的场景是基于客户端IP进行限流:
package main
import (
"net/http"
"sync"
"time"
"golang.org/x/time/rate"
)
type IPRateLimiter struct {
ips map[string]*rate.Limiter
mu *sync.RWMutex
r rate.Limit
b int
}
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
return &IPRateLimiter{
ips: make(map[string]*rate.Limiter),
mu: &sync.RWMutex{},
r: r,
b: b,
}
}
func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
i.mu.Lock()
defer i.mu.Unlock()
limiter := rate.NewLimiter(i.r, i.b)
i.ips[ip] = limiter
return limiter
}
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
i.mu.Lock()
limiter, exists := i.ips[ip]
if !exists {
i.mu.Unlock()
return i.AddIP(ip)
}
i.mu.Unlock()
return limiter
}
func limitMiddleware(next http.Handler) http.Handler {
limiter := NewIPRateLimiter(1, 5) // 每秒1个请求,桶大小5
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
if !limiter.GetLimiter(ip).Allow() {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
http.ListenAndServe(":8080", limitMiddleware(mux))
}
4. 分布式限流
对于分布式系统,可以使用Redis作为存储后端:
package main
import (
"net/http"
"github.com/ulule/limiter/v3"
"github.com/ulule/limiter/v3/drivers/middleware/stdlib"
"github.com/ulule/limiter/v3/drivers/store/redis"
)
func main() {
// 定义限流规则
rate := limiter.Rate{
Period: 1 * time.Hour,
Limit: 1000,
}
// 创建Redis存储
store, err := redis.NewStoreWithOptions(redis.Options{
Address: "localhost:6379",
Prefix: "limiter_",
})
if err != nil {
panic(err)
}
// 创建限流器实例
instance := limiter.New(store, rate)
// 创建中间件
middleware := stdlib.NewMiddleware(instance)
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
http.ListenAndServe(":8080", middleware.Handler(mux))
}
最佳实践建议
- 根据API端点的重要性设置不同的限流阈值
- 生产环境建议使用Redis等分布式存储
- 对认证用户和匿名用户使用不同的限流策略
- 在响应头中添加限流信息(X-RateLimit-Limit, X-RateLimit-Remaining等)
- 考虑实现滑动窗口算法以获得更精确的控制
以上示例提供了从简单到复杂的多种限流实现方式,您可以根据项目需求选择合适的方案。