ngx_lua是协程化脚本层,复用增强C模块能力,不替代C模块;所有I/O由Nginx C层驱动,Lua仅负责逻辑调度与数据组装;需避免阻塞、合理协同、注意性能与调试规范。

ngx_lua 模块不是用来“替代”C 模块的,而是以 Lua 脚本为胶水,复用、编排和增强已有 C 模块的能力。它本身不提供底层网络或内存操作,所有核心功能(如 socket 读写、变量获取、子请求发起)都依赖 Nginx C 层暴露的 API,并通过 LuaJIT FFI 或预封装接口调用。
理解 ngx_lua 的定位:协程化脚本层,非独立运行时
ngx_lua 运行在 Nginx event loop 内,每个请求对应一个轻量级 Lua 协程。它不能脱离 Nginx 生命周期独立存在,也不具备启动线程、监听端口、加载任意动态库等能力。所有 I/O 操作(如 ngx.socket.tcp()、ngx.location.capture())最终由 Nginx C 模块驱动,Lua 只负责逻辑调度与数据组装。
常见误区是试图用 Lua 实现高频系统调用(如频繁 open/read/close 文件),这会阻塞 worker 进程。正确做法是:用 C 模块做高性能原子操作(如共享内存计数、快速正则匹配),Lua 做条件判断、协议解析、组合多个子请求。
与 C 模块协同的三种典型方式
1. 读写 Nginx 变量与共享内存
C 模块可通过 ngx_http_set_complex_value_slot 或 ngx_shared_memory_add 暴露变量或 shm zone;Lua 使用 ngx.var.* 读写变量,用 resty.shm 或 ngx.shared.* 访问共享内存。例如:C 模块将设备指纹写入 $device_id,Lua 根据该值路由到不同 upstream。
2. 发起子请求并处理响应
Lua 调用 ngx.location.capture('/internal/auth') 触发内部 location,该 location 可由自定义 C 模块(如 auth_request 的增强版)处理。C 模块完成鉴权后设置响应头或返回 JSON,Lua 解析结果决定是否继续或返回 403。
3. 注册自定义指令并透传参数
C 模块定义配置指令(如 my_filter on|off),在 conf 解析阶段将开关状态存入 loc_conf;Lua 在运行时通过 ngx.ctx 或全局 table 缓存该配置,结合业务逻辑动态启用/禁用过滤行为。
性能关键点:避免阻塞与过度拷贝
— 不在 Lua 中做耗时计算(如 RSA 解密、大图缩放),应封装为异步 C 模块或交由后端服务
— 使用 ngx.escape_uri() 而非 string.gsub 避免重复分配内存
— 子请求优先用 capture_multi 批量发起,减少协程切换开销
— 共享内存读写加锁粒度要细,避免用 ngx.shared.myshm:set('key', val, exptime) 频繁覆盖,改用 incr 或 CAS 操作
调试与上线注意事项
— 开启 lua_code_cache off 仅用于开发,生产必须开启,否则每次请求重加载 Lua 代码,性能归零
— C 模块若使用全局静态变量或未线程安全的第三方库,与 ngx_lua 混合时需加锁或改用 per-worker 数据结构
— Lua 异常默认被捕获并记录 warn 日志,需配合 lua_need_request_body on 和 ngx.log(ngx.ERR, ...) 主动暴露错误上下文
— 使用 lua-resty-core 替代旧版内置 API,获得更稳定的底层封装和文档支持

















