生产环境必须替换 limiter 内存后端为 redis(推荐 redis 6+)或 ring.new,因 memory.new 非线程安全、多进程下计数器不共享;需自定义 keygenerator 解析 x-real-ip/x-forwarded-for 获取真实 ip;redis 客户端须配置 contexttimeout(≤200ms)和 minidleconns(≥5);建议分层限流(如 10s+300s)并用 skipper 排除健康检查路径。

Fiber 的 limiter 中间件默认不生效,生产环境必须换掉内存后端,否则限流就是摆设。
为什么 limiter.New 默认不防刷
因为 limiter.New 默认用的是 memory.New,它不是线程安全的。在 Docker 多副本、pm2 cluster 模式或任何多进程部署下,每个实例都维护自己的计数器,IP 请求量根本无法全局收敛。现象是:压测时 QPS 轻松破千,429 响应几乎为零,日志里也看不到拒绝记录。
- 单机调试(无 fork / 无并发 worker)→ 可临时用
memory.New - 生产环境 → 必须换成
redis.New(推荐 Redis 6+,支持 Lua 原子操作) - 没 Redis?可用
ring.New(环形缓冲区,内存低,但仍是单实例,仅适合轻量网关)
KeyGenerator 不写自定义逻辑,真实 IP 就会错
默认 KeyGenerator 只调 c.IP(),但绝大多数线上服务前面都有 Nginx、CDN 或云 WAF,真实客户端 IP 在 X-Real-IP 或 X-Forwarded-For 里。不处理会导致:整个 CDN 出口 IP 下的所有用户被一锅端封禁。
- 务必检查你前端代理是否透传了真实 IP,并确认字段名(常见有
X-Real-IP、X-Forwarded-For) - 示例中取
X-Real-IP,若为空才 fallback 到c.IP(),避免空字符串 key 冲突 - 别直接用
c.Get("X-Forwarded-For")—— 它可能含多个 IP(如1.1.1.1, 2.2.2.2),需切片取第一个
Redis 后端连不上?大概率是缺连接池和超时
redis.New 底层依赖 github.com/go-redis/redis/v8,但 Fiber 官方文档常省略关键配置。没设超时和连接池时,Redis 偶发延迟或抖动就会拖垮整个 HTTP 请求链路。
- 必须显式设置
ContextTimeout(建议 ≤ 200ms)和MinIdleConns(建议 ≥ 5) - 别复用全局
redis.Client实例而不做健康检查;连接断开后首次请求会卡住直到超时 - 错误日志里如果频繁出现
context deadline exceeded或connection refused,优先查 Redis 连接配置
真正容易被忽略的点是:限流不是配对 Max 和 Expiration 就完事——攻击者会卡窗口边界重放请求。比如设 60s 窗口,爬虫就每 59.9s 发一次。更有效的做法是分层:短窗口(10s)控爆破,长窗口(300s)控匀速,再加一个 Skipper 排除 /healthz、/metrics 这类路径,否则监控探针自己就把限流器打满了。











