Skip to content

Nginx Lua Lifecycle

1. Nginx 进程生命周期

Nginx 启动 → Master 进程 → Fork Worker → Worker 处理请求 → Worker 退出 → Master 退出。

在这个过程中,Lua 脚本可能运行在 配置阶段、进程启动阶段、请求处理阶段、定时器/异步阶段

2. Lua 执行生命周期阶段

(1) 配置阶段

  • init_by_lua / init_by_lua_file
  • 发生在 master 进程加载配置时(nginx -s reload 也会触发)
  • 全局只执行一次,适合初始化全局 Lua 环境、加载模块、预热缓存等
  • 注意:此时不能用 ngx.* 请求相关 API(因为没有请求上下文)

(2) Worker 初始化阶段

  • init_worker_by_lua / init_worker_by_lua_file
  • 每个 worker 进程启动时执行一次
  • 用来启动定时器(ngx.timer.at)、初始化 worker 级别状态
  • 同样不能用请求相关的 API,但可以用 cosocket API 连接数据库、Redis 等。

(3) 请求处理阶段(核心生命周期)

当请求进入 worker 时,Lua 脚本可挂在不同阶段:

  • set_by_lua
  • 执行在 rewrite 阶段之前,用于设置变量。
  • 要求必须返回值,执行环境有限制。
  • rewrite_by_lua
  • 在 rewrite 阶段运行,可改写 URI、做路由逻辑。
  • 可以使用大部分 ngx.* API。
  • access_by_lua
  • 在 access 阶段运行,可做鉴权、限流
  • 若调用 ngx.exit(403) 等可中止请求。
  • content_by_lua
  • 生成响应的主要阶段。
  • 可以写响应体、调用上游接口、反向代理等。
  • 最完整的请求上下文。
  • header_filter_by_lua
  • 在返回响应头时执行,可以修改响应头。
  • 无法再写响应体。
  • body_filter_by_lua
  • 在发送响应体时执行,可以修改响应体(比如做压缩/替换)。
  • 数据是流式的,可能分多次调用。
  • log_by_lua
  • 在请求完成后执行(log 阶段),适合写日志、打点。
  • 不影响请求结果,但仍有请求上下文。

(4) 请求外的异步生命周期

  • Timer 回调 (ngx.timer.at)
  • 在 worker 内调度执行,独立于请求上下文。
  • 可用于周期任务,如心跳、定时清理。

  • Light thread (coroutine)

  • ngx.thread.spawn 启动的“轻线程”,和请求生命周期绑定,请求结束后会被杀掉。

  • Cosocket API (ngx.socket.tcp, ngx.req.socket)

  • 支持非阻塞 IO,生命周期跟随请求(除非在定时器里)。

(5) Worker/进程退出阶段

  • 没有专门的 exit_worker_by_lua 钩子
  • Worker 退出时不会显式调用 Lua 脚本。
  • 如果需要清理,可以靠定时器或 log_by_lua 做善后。

3. 生命周期总结

Nginx master start
  └── init_by_lua (once per master)
Worker start
  └── init_worker_by_lua (once per worker)
Request start
  ├── set_by_lua
  ├── rewrite_by_lua
  ├── access_by_lua
  ├── content_by_lua
  ├── header_filter_by_lua
  ├── body_filter_by_lua
  └── log_by_lua
Background
  ├── timer callbacks
  ├── cosocket operations
  └── light threads
Worker exit
  └── (no direct lua hook)