Skip to content

API Rate Limiting #264

@test3207

Description

@test3207

Parent Issue: Epic 3.6: Production Deployment (#194)

Summary

在 Gateway 层(OpenResty + Redis)实现 API rate limiting,保护后端服务免受滥用。

Status: ✅ Gateway Implementation Complete

Gateway rate limiting has been implemented in m3w-k8s (commit 91fb0f8).

Architecture

Browser → Gateway (OpenResty + Lua + Redis) → Backend
                    ↓
              Rate Limiter
              - IP-based (未登录)
              - userId-based (已登录,从 JWT 解析)
              - endpoint-based (不同端点不同限制)

Rate Limit Strategy

限流维度

维度 Redis Key 格式 数据来源
IP rl:ip:{ip}:{endpoint}:{window} ngx.var.remote_addr
User rl:user:{userId}:{endpoint}:{window} JWT payload sub

限流配置

Endpoint 未登录 (IP) 已登录 (User) 说明
/api/logs 60/min 200/min 前端日志,高频
/api/auth/* 10/min N/A 防暴力破解
/api/upload/* N/A (401) 20/hour 防存储滥用
GET/HEAD 默认 60/min 300/min 读操作
POST/PUT/DELETE 默认 30/min 150/min 写操作

算法

使用 固定窗口计数(简单高效):

  • Key: rl:{type}:{id}:{path}:{minute}
  • 使用 INCR + EXPIRE
  • 窗口结束自动清理

响应头

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1703404800
Retry-After: 30  (仅 429 时)

Implementation Status

✅ Gateway (m3w-k8s) - COMPLETED

Created: ansible/playbooks/templates/gateway-rate-limit.lua.j2

  • Fixed window counter algorithm using Redis
  • Path normalization (IDs → :id to prevent key explosion)
  • Endpoint-specific rules (logs, auth, upload)
  • Fail-open design (allows requests if Redis is down)

Modified: ansible/playbooks/templates/gateway-routing.lua.j2

  • Integrated rate limiter call
  • Added traceId generation/passthrough
  • Added X-Gateway header

Modified: ansible/playbooks/templates/gateway-nginx.conf.j2

  • Added X-Trace-Id to CORS allowed headers
  • Added X-RateLimit-* headers to CORS expose headers

Modified: ansible/playbooks/templates/gateway-docker-compose.yml.j2

  • Added rate-limit.lua volume mount

Modified: ansible/playbooks/gateway.yaml

  • Added task to deploy rate-limit.lua

Deployment Required:

cd m3w-k8s
ansible-playbook -i ansible/inventory.ini ansible/playbooks/gateway.yaml --tags restart

⏳ Frontend (m3w) - OPTIONAL

Frontend graceful degradation is optional but recommended:

frontend/src/lib/api/router.ts

  • Handle 429 response
  • For /api/logs: silently drop (avoid log storm)
  • For other APIs: show toast notification

frontend/src/lib/logger-client.ts

  • On 429, drop logs instead of retrying

Testing

After deploying to gateways:

# Test rate limiting
for i in {1..100}; do 
  curl -s -o /dev/null -w "%{http_code}\n" https://gateway1.m3w.test3207.fun/api/health
done
# Should see 429 after ~60 requests

# Check headers
curl -I https://gateway1.m3w.test3207.fun/api/health
# X-RateLimit-Limit: 60
# X-RateLimit-Remaining: 59
# X-RateLimit-Reset: 1735344120

Monitoring (Grafana)

# Rate limit 触发统计
sum by (http_path) (count_over_time({service="m3w-gateway"} | json | http_status=429 [5m]))

# 按 IP 统计
topk(10, sum by (client_ip) (count_over_time({service="m3w-gateway"} | json | http_status=429 [1h])))

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions