如何在香港服务器中实现分布式限流?Nginx+Lua vs Redis Token Bucket实测对比

我一直为一家跨境电商平台提供后端架构支持,主要服务器部署在香港,既为了靠近亚洲用户,也为了享受香港网络自由和较低的跨境访问延迟。随着平台在东南亚、港澳台市场逐渐起量,我们面临的一个核心挑战是:如何在高并发访问场景下,实现稳定高效的分布式限流策略?
最初,我尝试在单台应用服务器上通过内存限流(如Guava RateLimiter)控制API速率,但很快发现其在多实例部署下几乎失效。用户请求可能打到任意节点,每个节点维护的计数器彼此独立,导致整个集群层面失控。
最终,我决定在香港服务器上部署两个分布式限流方案进行实测对比:
- 方案 A:基于 Nginx + Lua 的 Local Token Bucket
- 方案 B:基于 Redis 的 Centralized Token Bucket
下面是我在实际部署、调优、压测中的完整过程与最终结论。
一、需求与场景定义
我们的核心限流目标包括:
- 全局限流:整个系统每秒最多处理 X 个请求(比如 QPS 2000)。
- 用户级限流:每个用户每秒最多发送 Y 个请求(比如每秒 10 个)。
- IP 限流:防止恶意 IP 短时间内大量访问。
此外,还有一些非功能性要求:
- 分布式可扩展:能在多节点、多实例部署下统一管理速率;
- 高性能:不能引入明显延迟;
- 容错性好:即便某个限流组件宕机,不应导致请求全部失败。
二、方案 A:Nginx + Lua 实现本地令牌桶限流
技术选型
- OpenResty(Nginx + LuaJIT)
- lua-resty-limit-traffic 模块(官方推荐)
- 本地内存存储令牌桶,基于共享内存 lua_shared_dict
实现逻辑
lua_shared_dict limit_req_store 10m;
init_by_lua_block {
local limit_req = require "resty.limit.req"
limiter, err = limit_req.new("limit_req_store", 10, 20) -- rate=10/s, burst=20
}
access_by_lua_block {
local key = ngx.var.binary_remote_addr
local delay, err = limiter:incoming(key, true)
if not delay then
return ngx.exit(429)
end
if delay >= 0.001 then
ngx.sleep(delay)
end
}
优点
- 毫秒级处理速度,非常轻量;
- Nginx 层限流,防止非法请求进入业务层;
- 易于部署在香港本地服务器,无需外部依赖。
缺点
- 局部限流:在多台 Nginx 实例中,令牌桶是本地的;
- 不支持全局视角的限流,用户分散到不同实例上,限流精度降低;
- 难以实现动态调整规则。
三、方案 B:Redis Token Bucket 实现全局限流
技术选型
- Redis 7.x(部署在香港阿里云实例,主从哨兵集群)
- Lua 脚本实现令牌桶算法
- 应用层或 Nginx Lua 通过 Redis 统一请求分发控制
Lua 脚本核心逻辑(Redis Token Bucket)
local key = KEYS[1]
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])
local last_tokens = tonumber(redis.call("GET", key .. ":tokens")) or capacity
local last_refreshed = tonumber(redis.call("GET", key .. ":ts")) or now
local delta = math.max(0, now - last_refreshed)
local new_tokens = math.min(capacity, last_tokens + (delta * rate))
if new_tokens < requested then
return 0
else
redis.call("SET", key .. ":tokens", new_tokens - requested)
redis.call("SET", key .. ":ts", now)
return 1
end
每次请求前调用 Redis 判断是否可以放行,Redis 脚本原子性保障一致性。
优点
- 真正分布式全局限流:所有实例共享 Redis 作为速率源;
- 精度高,动态配置灵活;
- 支持多级策略:IP、用户、API 维度分别建桶。
缺点
- Redis 成为瓶颈,高并发下需要部署 Redis Cluster;
- 请求延迟较 Nginx + Lua 稍高(约 0.3~0.6ms);
- 需处理 Redis 网络超时、单点故障等容错逻辑。
四、压测对比(香港本地服务器)
我分别在两套部署环境中进行压测(AB 工具 + K6 + 自研脚本),测试环境为香港 3 台 ECS 实例,1Gbps 内网带宽。
| 指标 | Nginx + Lua | Redis Token Bucket |
|---|---|---|
| 平均响应时间 | 0.4ms | 1.2ms |
| 吞吐量(请求/s) | 14,000 | 9,500 |
| 限流精度(±1s) | 中(±10~15%) | 高(±1~2%) |
| 多实例一致性 | 差 | 优 |
| 可动态调整限速规则 | 否(需 reload) | 是(热更新配置) |
| 容错性 | 高(完全本地) | 中(依赖 Redis 连通性) |
五、最终方案:混合架构
最后我们采用了一个 混合限流架构:
- Nginx + Lua 限流作为第一道防线,防止恶意流量;
- Redis Token Bucket 实现核心业务限流,确保策略一致性;
- 结合 Kong / APISIX 支持更灵活的限流插件;
- 统一配置中心动态推送规则(基于 etcd + Lua);
- Prometheus + Grafana 实时监控各层限流状态和命中率。
六、总结与建议
从这次在香港服务器上实测来看:
- 小型部署、边缘网关、防火墙式限流推荐 Nginx + Lua;
- 多节点大规模分布式系统推荐 Redis Token Bucket 或 Kafka 方案;
- 限流只是手段,底层服务弹性能力同样重要。
限流没有银弹,唯有根据业务场景权衡取舍,才能实现真正稳定、高效、可扩展的流控架构。
如果你也在香港服务器环境下部署系统,并面临类似限流挑战,欢迎和我一起交流架构实践与调优策略。