golang,go,博客,开源,编程
在 Gin 中实现基于 IP 的请求并发限制可以使用自定义中间件来限制每个 IP 地址的并发请求数。这样,每个 IP 地址的请求会有独立的并发限制,而不会影响其他 IP 的请求。通常,可以使用 map
存储每个 IP 的并发状态,并用信号量或计数器来限制并发请求数。
以下是一个示例代码,展示如何根据 IP 限制请求的并发数:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"sync"
"time"
)
// 并发限制结构体,保存每个 IP 的并发请求信息
type IPConcurrencyLimiter struct {
mu sync.Mutex
limitMap map[string]chan struct{}
maxConcurrency int
}
// 创建新的并发限制器
func NewIPConcurrencyLimiter(maxConcurrency int) *IPConcurrencyLimiter {
return &IPConcurrencyLimiter{
limitMap: make(map[string]chan struct{}),
maxConcurrency: maxConcurrency,
}
}
// 请求并发限制中间件
func (limiter *IPConcurrencyLimiter) LimitConcurrencyByIP() gin.HandlerFunc {
return func(c *gin.Context) {
// 获取客户端的 IP 地址
clientIP := c.ClientIP()
// 锁定 limiter 结构,确保线程安全
limiter.mu.Lock()
// 如果该 IP 的信号通道还没有创建,则创建
if _, exists := limiter.limitMap[clientIP]; !exists {
limiter.limitMap[clientIP] = make(chan struct{}, limiter.maxConcurrency)
}
// 解锁
limiter.mu.Unlock()
// 获取该 IP 的信号通道
ipSemaphore := limiter.limitMap[clientIP]
// 如果通道已满,表示该 IP 的并发请求数已达上限,拒绝请求
select {
case ipSemaphore <- struct{}{}:
// 该 IP 请求被允许,继续处理请求
c.Next()
// 请求处理完后,释放该 IP 的一个并发请求信号
<-ipSemaphore
default:
// 如果并发请求数已达上限,返回 429 Too Many Requests 错误
c.JSON(http.StatusTooManyRequests, gin.H{
"message": "Too many requests from your IP, please try again later.",
})
c.Abort() // 终止请求
}
}
}
func main() {
// 创建并发限制器,最大并发数为 2
limiter := NewIPConcurrencyLimiter(2)
// 创建 Gin 实例
r := gin.Default()
// 应用并发限制中间件
r.Use(limiter.LimitConcurrencyByIP())
// 示例路由
r.GET("/example", func(c *gin.Context) {
// 模拟处理请求的时间
time.Sleep(2 * time.Second)
c.JSON(http.StatusOK, gin.H{
"message": "Request processed successfully",
})
})
// 启动服务器
r.Run(":8080")
}
IPConcurrencyLimiter
结构体:
limitMap
:一个 map
用于存储每个 IP 的并发请求通道。每个 IP 地址都会有一个独立的 chan struct{}
类型的通道,用来限制该 IP 的并发请求数。maxConcurrency
:每个 IP 地址的最大并发请求数。LimitConcurrencyByIP
中间件:
chan struct{}
),每个通道的容量限制了该 IP 的最大并发请求数。chan struct{}
)作为信号量,每当一个请求到达时,尝试向该 IP 地址的通道发送一个信号。如果通道满了,表示并发数已达上限,拒绝请求。运行程序后,尝试发送多个请求:
正常请求(并发请求数未超过限制):
curl http://localhost:8080/example
超过并发限制的请求(例如,发送多个并发请求):
curl http://localhost:8080/example
curl http://localhost:8080/example
curl http://localhost:8080/example
假设每个 IP 的最大并发限制为 2,那么前三个请求中,只有前两个会被处理,第三个请求将会被拒绝并返回如下响应:
{
"message": "Too many requests from your IP, please try again later."
}
limitMap
中的无效 IP 记录。通过在 Gin 中实现基于 IP 的并发限制,你可以有效地控制每个 IP 的请求并发数,避免某个 IP 过度占用服务器资源,防止恶意攻击或滥用。同时,你可以灵活调整并发限制,增强应用的可扩展性和可靠性。