限流控制 #
一、限流概述 #
1.1 什么是限流 #
限流是控制请求频率的机制,防止系统过载和滥用。
1.2 限流算法 #
| 算法 | 说明 |
|---|---|
| 固定窗口 | 固定时间窗口内限制请求数 |
| 滑动窗口 | 平滑的请求限制 |
| 令牌桶 | 按速率生成令牌 |
| 漏桶 | 恒定速率处理请求 |
二、使用内置中间件 #
2.1 基本配置 #
go
package main
import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/limiter"
)
func main() {
app := fiber.New()
app.Use(limiter.New(limiter.Config{
Max: 100,
Expiration: 1 * time.Minute,
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello")
})
app.Listen(":3000")
}
2.2 完整配置 #
go
app.Use(limiter.New(limiter.Config{
// 最大请求数
Max: 100,
// 时间窗口
Expiration: 1 * time.Minute,
// 存储后端
Storage: memory.New(),
// 限流键生成
KeyGenerator: func(c *fiber.Ctx) string {
return c.IP()
},
// 限流响应
LimitReached: func(c *fiber.Ctx) error {
return c.Status(429).JSON(fiber.Map{
"error": "Too many requests",
})
},
// 跳过条件
Next: func(c *fiber.Ctx) bool {
return c.Path() == "/health"
},
}))
三、自定义限流 #
3.1 基于IP限流 #
go
import "golang.org/x/time/rate"
func RateLimitMiddleware(rps int, burst int) fiber.Handler {
limiters := make(map[string]*rate.Limiter)
mu := sync.RWMutex{}
return func(c *fiber.Ctx) error {
ip := c.IP()
mu.RLock()
limiter, exists := limiters[ip]
mu.RUnlock()
if !exists {
mu.Lock()
limiter = rate.NewLimiter(rate.Limit(rps), burst)
limiters[ip] = limiter
mu.Unlock()
}
if !limiter.Allow() {
return c.Status(429).JSON(fiber.Map{
"error": "Too many requests",
})
}
return c.Next()
}
}
// 使用
app.Use(RateLimitMiddleware(100, 20))
3.2 基于用户限流 #
go
func UserRateLimit(rps int, burst int) fiber.Handler {
limiters := make(map[string]*rate.Limiter)
mu := sync.RWMutex{}
return func(c *fiber.Ctx) error {
userID := c.Locals("user_id")
if userID == nil {
return c.Next()
}
key := userID.(string)
mu.RLock()
limiter, exists := limiters[key]
mu.RUnlock()
if !exists {
mu.Lock()
limiter = rate.NewLimiter(rate.Limit(rps), burst)
limiters[key] = limiter
mu.Unlock()
}
if !limiter.Allow() {
return c.Status(429).JSON(fiber.Map{
"error": "Rate limit exceeded",
})
}
return c.Next()
}
}
3.3 滑动窗口限流 #
go
type SlidingWindow struct {
requests []time.Time
window time.Duration
max int
mu sync.Mutex
}
func NewSlidingWindow(window time.Duration, max int) *SlidingWindow {
return &SlidingWindow{
requests: make([]time.Time, 0),
window: window,
max: max,
}
}
func (sw *SlidingWindow) Allow() bool {
sw.mu.Lock()
defer sw.mu.Unlock()
now := time.Now()
cutoff := now.Add(-sw.window)
// 移除过期请求
valid := make([]time.Time, 0)
for _, t := range sw.requests {
if t.After(cutoff) {
valid = append(valid, t)
}
}
sw.requests = valid
// 检查是否超限
if len(sw.requests) >= sw.max {
return false
}
sw.requests = append(sw.requests, now)
return true
}
四、Redis分布式限流 #
4.1 Redis限流 #
go
import "github.com/gofiber/storage/redis"
func main() {
storage := redis.New(redis.Config{
Host: "localhost",
Port: 6379,
})
app := fiber.New()
app.Use(limiter.New(limiter.Config{
Max: 100,
Expiration: 1 * time.Minute,
Storage: storage,
}))
app.Listen(":3000")
}
五、分级限流 #
5.1 不同路由不同限制 #
go
func main() {
app := fiber.New()
// 全局限流
app.Use(limiter.New(limiter.Config{
Max: 1000,
Expiration: 1 * time.Minute,
}))
// API限流
api := app.Group("/api", limiter.New(limiter.Config{
Max: 100,
Expiration: 1 * time.Minute,
}))
// 登录限流(更严格)
app.Post("/login", limiter.New(limiter.Config{
Max: 5,
Expiration: 1 * time.Minute,
}), loginHandler)
app.Listen(":3000")
}
六、总结 #
6.1 限流策略 #
| 策略 | 说明 |
|---|---|
| 全局限流 | 保护整体系统 |
| 路由限流 | 保护关键接口 |
| 用户限流 | 防止单用户滥用 |
| IP限流 | 防止恶意攻击 |
6.2 下一步 #
现在你已经掌握了限流控制,接下来让我们学习 优雅关闭,了解如何安全关闭服务!
最后更新:2026-03-28