nginx限流依托事件驱动架构,在ngx_http_preaccess_phase阶段基于共享内存zone与漏桶算法实现纳秒级原子操作,全程零阻塞、无系统调用;burst与nodelay行为均由事件循环调度,不依赖线程或队列。

Nginx 的事件驱动架构是它能在高并发下稳定限流的核心基础,不是靠“加线程”或“轮询检查”,而是把限流判断完全融入事件处理流水线中,做到零阻塞、低延迟、无系统调用。
限流动作发生在请求进入的最早阶段,且全程内存操作
Nginx 在 NGX_HTTP_PREACCESS_PHASE 阶段就完成限流判定——此时请求头刚解析完,还没走路由、鉴权或转发逻辑。整个过程:
- 从共享内存 zone 中按 key(如
$binary_remote_addr)快速查状态; - 基于漏桶算法更新时间戳和计数器;
- 所有操作通过原子指令完成,无需加锁;
- 全程在 CPU cache 和 slab 分配的共享内存中进行,不触发 syscalls,也不访问磁盘或网络。
epoll 让限流不成为性能瓶颈
每个 worker 进程绑定一个 epoll 实例,而限流状态存放在所有 worker 共享的内存 zone 中:
- 新连接或请求到达时,epoll_wait 返回就绪事件,worker 立即响应;
- 查限流状态只是一次内存寻址 + 原子读写,耗时在纳秒级;
- 即使 QPS 达到数万,只要共享内存 zone 不满、key 不复杂,限流模块本身几乎不增加 CPU 开销。
共享内存 zone 是协同关键
zone 不是每个 worker 自己维护一份,而是由 master 进程初始化、所有 worker 映射同一块内存:
- 使用 slab 分配管理 slot,避免频繁 malloc/free;
-
$binary_remote_addr比$remote_addr节省约 75% 内存(IPv4 下从 15 字节降到 4 字节); - 10MB zone 约可存 16 万个 IP 记录,预估业务 IP 规模后合理设置 size,避免频繁淘汰或浪费。
burst 和 nodelay 的行为也依赖事件模型
-
burst=20并非开个队列缓存请求,而是允许最多 20 个请求“透支”令牌,它们仍由 epoll 立即调度处理; -
nodelay表示不排队等待,透支请求立刻放行或拒绝,响应延迟保持在 sub-millisecond 级; - 若不用
nodelay,超出速率的请求会进入内部微队列,按固定间隔(如 100ms/个)释放,这依然由事件循环驱动,不启新线程。
不复杂但容易忽略











