随着互联网和移动互联网的快速发展,服务器面对的压力越来越大,如何限制客户端对服务器的请求,避免服务器崩溃成为了一个大问题。在实际项目中,我们经常需要限制ip的请求数,保证网站的可用性。
在这里,我们将介绍如何使用Golang实现IP限流。总的来说,我们将利用令牌桶算法来实现基于IP地址的限流。 令牌桶算法是一种流量控制算法,它允许一定数量的请求在一定时间内通过并限制一段时间内的请求流量。
实现细节
令牌桶算法以恒定速率往桶中放入令牌,令牌桶有一个容量限制,意味着桶中的令牌数量不会超过容量。对于每个请求,从桶中移除一个令牌,如果桶中没有令牌,则请求无法通过。
为了实现基于IP地址的限流,我们需要为每个IP地址创建一个令牌桶,每个令牌桶都有一个最大容量和一个恒定的速度。当请求到来时,我们从令牌桶中移除一个令牌,如果桶中没有令牌,则拒绝请求。
立即学习“go语言免费学习笔记(深入)”;
基于此,我们可以定义一个IP限流器:
type IPRateLimiter struct {
limiterBuckets map[string]*rate.Limiter
mu *sync.Mutex
r rate.Limit
b int
}其中, limiterBuckets 是一个映射,将字符串 IP 地址映射到令牌桶。mu 是一个互斥锁, r 是速率限制器每秒放入令牌的速率, b 是令牌桶的容量。
为了为每个IP地址创建令牌桶,我们定义一个函数NewIPRateLimiter :
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
return &IPRateLimiter{
limiterBuckets: make(map[string]*rate.Limiter),
mu: &sync.Mutex{},
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.limiterBuckets[ip] = limiter
return limiter
}AddIP函数用于为IP地址创建令牌桶。如果为该IP地址创建了令牌桶,则返回现有的令牌桶,否则创建一个新的令牌桶并返回。
最后,我们可以实现HTTP中间件来限制IP地址的请求数:
func (i *IPRateLimiter) Limit(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
limiter, ok := i.limiterBuckets[ip]
if !ok {
limiter = i.AddIP(ip)
}
if !limiter.Allow() {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}该中间件允许在指定的速率和容量下通过请求。如果请求数超过容量,则返回HTTP错误代码429(太多请求)。
完整代码如下:
package main
import (
"net/http"
"strconv"
"sync"
"golang.org/x/time/rate"
)
type IPRateLimiter struct {
limiterBuckets map[string]*rate.Limiter
mu *sync.Mutex
r rate.Limit
b int
}
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
return &IPRateLimiter{
limiterBuckets: make(map[string]*rate.Limiter),
mu: &sync.Mutex{},
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.limiterBuckets[ip] = limiter
return limiter
}
func (i *IPRateLimiter) Limit(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
limiter, ok := i.limiterBuckets[ip]
if !ok {
limiter = i.AddIP(ip)
}
if !limiter.Allow() {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("welcome."))
}
func main() {
limit := rate.Limit(10) // 速率,每秒放入令牌的数量
capacity := 100 // 容量,桶的大小
ipRateLimiter := NewIPRateLimiter(limit, capacity)
http.Handle("/", ipRateLimiter.Limit(http.HandlerFunc(IndexHandler)))
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}在这个例子中,我们允许每秒放入10个令牌,并限制桶的容量为100。这意味着该限制器可以处理每秒最多10个请求,但如果对同一IP地址的请求达到100个,则无法通过请求。同时,我们定义了一个简单的处理程序,它将响应“欢迎”。
结论
在本文中,我们使用Golang实现了IP限流,采用令牌桶算法来限制每个IP地址的请求速率。这种方法可以实现一个简单而有效的限流机制,并且可以在Golang中方便地实现。当你在编写高并发的网络应用程序时,这可能是一个非常有用的技巧。
以上就是Golang实现ip限流的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号