Nginx配合lua-resty-limit-traffic实现动态令牌桶限流,核心是运行时热更新速率与突发值:通过shared_dict存储用户级配置,access_by_lua_block中按X-User-ID查覆盖默认参数,并启用advanced header输出实时指标。

使用 nginx 配合 lua-resty-limit-traffic 实现动态令牌桶限流,核心在于:把限流策略从静态配置转向运行时可调,同时保持高性能和低延迟。下面以真实可运行的场景为例,一步步说明关键配置与逻辑。
一、安装依赖并启用 Lua 支持
确保 Nginx 编译时已集成 lua-nginx-module(OpenResty 默认自带),并安装 lua-resty-limit-traffic 库:
- 若用 OpenResty,该库通常已预装在
/usr/local/openresty/lualib/resty/下 - 手动安装可执行:
luarocks install lua-resty-limit-traffic - 确认
init_by_lua_block和access_by_lua_block能正常执行
二、定义动态令牌桶对象(按 key 区分)
令牌桶需支持不同维度的限流(如用户 ID、API 路径、IP),且速率可热更新。示例中以请求头 X-User-ID 为 key:
lua_shared_dict my_limit_store 10m;
<p>server {
location /api/v1/data {
access_by_lua_block {
local limit = require "resty.limit.traffic"
local lim, err = limit.new("my_limit_store", {
rate = 10, -- 初始 10 r/s
burst = 20, -- 最多突发 20 个令牌
key = ngx.var.http_x_user_id or ngx.var.remote_addr,
rejected_code = 429,
header_mode = "advanced"
})
if not lim then
ngx.log(ngx.ERR, "failed to instantiate a limiter: ", err)
return ngx.exit(500)
end</p><pre class="brush:php;toolbar:false;"> local delay, err = lim:incoming()
if err then
if err == "rejected" then
return ngx.exit(429)
end
ngx.log(ngx.ERR, "failed to limit: ", err)
return ngx.exit(500)
end
}
proxy_pass http://backend;
}}
三、运行时动态调整限流参数
不重启 Nginx 即可修改速率或突发值,通过共享字典 + 自定义接口实现:
- 新增管理接口
POST /admin/limit/update,接收 JSON:{"user_id":"u123","rate":5,"burst":10} - 在
content_by_lua_block中解析参数,写入shared_dict的自定义 key(如"limit:u123") - 修改限流逻辑:在
limit.new前先查共享字典,若存在用户专属配置则覆盖默认值
示例片段(简化):
local conf = shared_dict:get("limit:" .. user_key) or {}
local actual_rate = conf.rate or 10
local actual_burst = conf.burst or 20
<p>local lim, err = limit.new("my_limit_store", {
rate = actual_rate,
burst = actual_burst,
key = user_key,
...
})</p>
四、验证与观测指标输出
启用 header_mode = "advanced" 后,响应头自动包含限流状态:
-
X-RateLimit-Limit:当前桶容量(burst) -
X-RateLimit-Remaining:剩余令牌数 -
X-RateLimit-Reset:下次重置时间戳(秒级)
配合日志可记录实际消耗情况:log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$sent_http_x_ratelimit_remaining"'
不复杂但容易忽略:令牌桶的 key 必须具备业务唯一性且不可被客户端伪造;共享字典更新需加锁或用 CAS 机制防并发覆盖;突发值(burst)不宜设得过大,否则削弱限流效果。











