How to Rate Limit HTTP Requests
发布日期:2021-05-16 21:14:01 浏览次数:20 分类:精选文章

本文共 3602 字,大约阅读时间需要 12 分钟。

HTTP速率限制实现指南

1. 简单速率限制

在Go语言中,使用golang.org/x/time/rate包可以轻松实现速率限制功能。这是一个功能强大、维护良好的库,适合处理各种速率限制场景。然而,如果你想要一个轻量级的解决方案,或者想自己实现,可以按照以下步骤操作:

1.1 安装所需依赖

首先,安装速率限制包:

go get golang.org/x/time/rate

1.2 创建项目结构

创建一个包含limit.gomain.go的目录:

mkdir ratelimit-democd ratelimit-demotouch limit.go main.go

1.3 实现速率限制中枢

limit.go文件中定义速率限制器:

package mainimport (    "net/http"    "golang.org/x/time/rate")var limiter = rate.NewLimiter(2, 5)func limit(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        if limiter.Allow() == false {            http.Error(w, http.StatusText(429), http.StatusTooManyRequests)            return        }        next.ServeHTTP(w, r)    })}

1.4 整合速率限制到服务器

main.go文件中,使用limit中枢包装路由:

package mainimport (    "net/http")func main() {    mux := http.NewServeMux()    mux.HandleFunc("/", okHandler)        http.ListenAndServe(":4000", limit(mux))}func okHandler(w http.ResponseWriter, r *http.Request) {    w.Write([]byte("OK"))}

1.5 测试速率限制

运行应用并使用curl发送请求观察结果:

go run *.gocurl -i localhost:4000

1.6 处理用户速率

如果需要按用户(如IP地址)进行速率限制,可以在limit.go中扩展实现。以下是实现细节:

package mainimport (    "net/http"    "sync"    "golang.org/x/time/rate")var visitors = make(map[string]*rate.Limiter)var mtx sync.Mutex// 添加用户速率限制func addVisitor(ip string) *rate.Limiter {    limiter := rate.NewLimiter(2, 5)    mtx.Lock()    visitors[ip] = limiter    mtx.Unlock()    return limiter}// 获取或创建用户速率限制func getVisitor(ip string) *rate.Limiter {    mtx.Lock()    limiter, exists := visitors[ip]    if !exists {        mtx.Unlock()        return addVisitor(ip)    }    mtx.Unlock()    return limiter}// 更新用户最后访问时间// 同时清除过期访问记录func limit(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        limiter := getVisitor(r.RemoteAddr)        if limiter.Allow() == false {            http.Error(w, http.StatusText(429), http.StatusTooManyRequests)            return        }        next.ServeHTTP(w, r)    })}

2. 清理过期访问

为了避免内存泄漏,可以在后台执行清理任务:

package mainimport (    "net/http"    "sync"    "time"    "golang.org/x/time/rate")type visitor struct {    limiter  *rate.Limiter    lastSeen time.Time}var visitors = make(map[string]*visitor)var mtx sync.Mutex// 初始化清理任务func init() {    go cleanupVisitors()}// 清理定时任务func cleanupVisitors() {    for {        time.Sleep(time.Minute)        mtx.Lock()        for ip, v := range visitors {            if time.Now().Sub(v.lastSeen) > 3*time.Minute {                delete(visitors, ip)            }        }        mtx.Unlock()    }}// 添加新访客func addVisitor(ip string) *rate.Limiter {    limiter := rate.NewLimiter(2, 5)    mtx.Lock()    visitors[ip] = &visitor{limiter: limiter, lastSeen: time.Now()}    mtx.Unlock()    return limiter}// 获取或创建访客速率限制func getVisitor(ip string) *rate.Limiter {    mtx.Lock()    v, exists := visitors[ip]    if !exists {        mtx.Unlock()        return addVisitor(ip)    }    v.lastSeen = time.Now()    mtx.Unlock()    return v.limiter}// 应用速率限制中枢func limit(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        limiter := getVisitor(r.RemoteAddr)        if limiter.Allow() == false {            http.Error(w, http.StatusText(429), http.StatusTooManyRequests)            return        }        next.ServeHTTP(w, r)    })}

2. 性能优化建议

2.1 使用sync.RWMutex代替sync.Mutex以降低 contention。

2.2 根据实际需求定制化配置参数。

2.3 考虑将速率限制器包装为可配置模块,以支持不同的资源和策略。

2.4 使用VulnChecker进行性能测试,确保系统在高负载下稳定运行。

3. 总结

通过以上方法,你可以轻松实现HTTP服务器的速率限制功能。无论是全局速率限制,还是按用户(如IP地址)定制速率限制,都可以根据实际需求选择合适的实现方案。Go语言的优雅语法和高效的标准库,使得实现和迭代依然非常简单和高效。

上一篇:golang maps in action
下一篇:How to initialized a nested []struct?

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月26日 16时35分30秒