OpenResty + Lua 可基于 lua-resty-limit-traffic 模块在 access_by_lua_block 阶段实现纯内存限流,无需修改 Nginx C 代码或依赖 Redis;需配置 lua_shared_dict,按 IP 或“IP:method:uri”复合键限流,并返回标准 429 响应及 X-RateLimit 头。

用 OpenResty + Lua 写一个简易 API 网关限流器,核心是利用 lua-resty-limit-traffic 模块,在 access_by_lua_block 阶段拦截并控制请求速率。不需要改 Nginx C 代码,也不依赖外部服务(如 Redis),纯内存共享字典即可实现高并发限流。
准备基础环境
确保你使用的是 OpenResty(不是原生 Nginx),版本建议 ≥ 1.19.3.2。验证方式:
- 运行
openresty -v,输出应含luajit - 检查模块是否可用:
lua -e "require 'resty.limit.req'"不报错即正常 - 在
nginx.conf的http块中声明共享内存区(必须):lua_shared_dict my_limit_req_store 10m;
按 IP 限流:每秒最多 10 次请求
在 location 或 server 块中添加如下 Lua 逻辑:
-
access_by_lua_block中初始化限流器:local limit_req = require "resty.limit.req"<br>local lim, err = limit_req.new("my_limit_req_store", 10, 10)
→ 表示每秒最多 10 个请求,桶容量也是 10(允许短时突增) - 用客户端真实 IP 作为 key(注意穿透代理时需用
$realip_remote_addr):local key = ngx.var.binary_remote_addr - 执行限流判断:
local delay, err = lim:incoming(key, true)<br>if err == "rejected" then<br> ngx.status = 429<br> ngx.header["X-RateLimit-Limit"] = "10"<br> ngx.header["X-RateLimit-Remaining"] = "0"<br> ngx.say('{"error":"rate limited"}')<br> return<br>end
按接口路径 + IP 联合限流
更贴近生产场景:同一用户访问 /api/user/profile 和 /api/order/list 应分别计数。
- 构造复合 key:
local key = ngx.var.binary_remote_addr .. ":" .. ngx.var.uri - 或加 method 区分读写:
local key = ngx.var.binary_remote_addr .. ":" .. ngx.var.request_method .. ":" .. ngx.var.uri - 注意 URI 含参数时建议先规范化(如去掉 query string),避免相同接口因参数顺序不同被算作多个 key
返回友好响应与头信息
限流响应不应只是 503 或空页,建议统一 JSON 格式并带标准限流头:
- 设置响应头:
ngx.header["X-RateLimit-Limit"] = "10"<br>ngx.header["X-RateLimit-Remaining"] = tostring(10 - (lim:count(key) or 0))<br>ngx.header["X-RateLimit-Reset"] = ngx.time() + 1
- 返回体示例:
ngx.status = 429<br>ngx.header["Content-Type"] = "application/json"<br>ngx.say('{"code":429,"msg":"Too Many Requests","retry_after":1}')<br>return


















