限流控制 #

一、限流概述 #

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