worker_connections 是每个 worker 进程的 TCP 连接上限,不等于 Lua 协程并发数;真实吞吐受非阻塞 I/O、协程调度、系统 fd 与内存资源三重制约,需协同调优连接层、协程层和资源层配置。

worker_connections 和 Lua 协程的并发承载能力,不是简单相加或叠加的关系,而是存在资源竞争、调度耦合与执行模型差异的三层制约——它决定了“能连上”和“能跑完”的边界。
worker_connections 是连接入口上限,不是 Lua 执行槽位
这个参数只控制每个 worker 进程最多维持多少个客户端 TCP 连接(含 keepalive 空闲连接),不涉及请求是否被 Lua 处理、处理多久、是否阻塞。哪怕你设了 worker_connections 65535,只要 Lua 脚本里写了 os.execute("sleep 2") 或调用未封装为非阻塞的 C 库函数,一个协程就会卡住整个 worker 的事件循环,导致其他连接无法及时响应。
真正影响 Lua 并发吞吐的,是:
- 每个请求触发的 Lua 协程是否全程异步(依赖 lua-resty-core + resty-http / redis 等非阻塞库)
- 协程栈大小(lua_setstack 默认约 1MB/协程,但 Nginx 中实际受 lua_code_cache off 和 lua_socket_pool_size 影响更大)
- 单个 worker 内可同时活跃的协程数,受限于内存与事件循环调度粒度,一般建议单 worker 不超过 3000–5000 个活跃 Lua 协程(非连接数)
Lua 协程本身不突破 worker_connections 瓶颈
即使所有 Lua 逻辑都写成纯协程+非阻塞 I/O,Nginx 仍需先通过 epoll 收到连接、解析请求头、分发给 Lua 阶段——这些步骤仍消耗连接槽位。也就是说:
- 一个 HTTP/1.1 keepalive 连接可复用承载数百个请求,每个请求启动一个 Lua 协程 → 此时 worker_connections = 4096 可支撑远高于 4096 的总请求数
- 但若每个请求都新建连接(短连接 API),且 Lua 协程平均耗时 50ms,则真实 QPS ≈ 4096 ÷ 0.05 ≈ 8 万(理论极限,忽略系统开销)→ 实际常因上下文切换、GC 停顿压到 3–5 万
关键限制点在于:
- lua_max_running_timers(默认 1024):影响定时器类协程并发数
- lua_max_pending_timers(默认 4096):决定待触发定时器上限
- lua_socket_pool_size(默认 30):上游连接池大小,直接影响反向代理型 Lua 脚本的并发伸缩性
协同调优才能释放真实承载力
要让 Lua 在高连接场景下稳定发挥,必须同步收紧三类配置:
- 连接层:启用 keepalive_timeout 60s + keepalive_requests 1000,减少连接反复创建销毁开销
- 协程层:设置 lua_code_cache on(生产必须),避免每次请求重编译;lua_socket_connect_timeout 1s 防止上游卡死拖垮全部协程
- 资源层:将 worker_rlimit_nofile 设为 ≥ worker_processes × worker_connections × 1.5(留出 Lua socket、日志、临时文件等 fd 余量)
典型组合示例(4 核服务器):
worker_processes 4;
events { worker_connections 8192; use epoll; multi_accept on; }
http { lua_shared_dict limit 10m; lua_socket_pool_size 200; ... }
→ 理论连接上限 32768,配合良好 Lua 脚本,可持续承载 1.5–2.5 万活跃协程级请求处理(非连接数)
别忽视运行时指标验证
配置再合理,也要靠数据确认是否真扛得住:
- nginx -s reload 后检查 error.log 是否有 "lua coroutine stack overflow" 或 "too many open files"
- 用 ss -s 观察 total: sockets: 是否接近 ulimit 上限
- 通过 lua-resty-metrics 或自定义 shared_dict 计数,统计单位时间实际启动的协程数与平均生命周期
- 若发现 Active connections 长期 > 85% worker_connections,但 QPS 却上不去,大概率是 Lua 层出现隐式阻塞(如未用 cosocket 的 DNS 查询、JSON 解析过大 body)


















