7.9.2 LuaJIT与ngx_lua基础

LuaJIT与ngx_lua基础#

LuaJIT 是 OpenResty 的高性能 Lua 运行时,配合 ngx_lua 可在 Nginx 事件驱动模型中执行 Lua 代码,实现高并发下的动态逻辑处理。本节从执行模型、阶段与 API、可运行示例、安装与排错、练习任务展开。

原理草图:Nginx 事件模型与 Lua 阶段#

文章图片

运行环境与执行模型#

  • LuaJIT 特性:JIT 编译、FFI 接口、低开销协程,适合高并发场景的轻量逻辑。
  • ngx_lua 机制:将 Lua 代码嵌入 Nginx 指令中,在不同阶段(phase)执行。
  • 事件驱动:非阻塞 I/O 为核心,阻塞操作会导致性能下降或请求堆积。

Nginx 阶段与执行上下文示例#

# /usr/local/openresty/nginx/conf/nginx.conf
worker_processes  1;

events { worker_connections 1024; }

http {
    lua_shared_dict metrics 10m;

    server {
        listen 8080;

        rewrite_by_lua_block {
            ngx.var.request_id = ngx.var.request_id or ngx.time()
        }

        access_by_lua_block {
            local dict = ngx.shared.metrics
            local key = ngx.var.remote_addr
            local n = dict:incr(key, 1, 0)
            if n > 100 then
                return ngx.exit(429)
            end
        }

        content_by_lua_block {
            ngx.header["Content-Type"] = "application/json"
            ngx.say('{"ok":true,"id":"', ngx.var.request_id, '"}')
        }

        log_by_lua_block {
            ngx.log(ngx.INFO, "req_id=", ngx.var.request_id)
        }
    }
}

常用 API 与关键对象示例#

-- /usr/local/openresty/nginx/lua/hello.lua
local args = ngx.req.get_uri_args()
local name = args.name or "world"

ngx.status = 200
ngx.header["Content-Type"] = "text/plain"
ngx.say("hello ", name)

-- 共享字典计数
local dict = ngx.shared.metrics
local count = dict:incr("hello_count", 1, 0)
ngx.say("count=", count)

在配置中引用模块文件:

# /usr/local/openresty/nginx/conf/nginx.conf
http {
    lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";
    lua_shared_dict metrics 10m;

    server {
        listen 8080;
        location /hello {
            content_by_lua_file /usr/local/openresty/nginx/lua/hello.lua;
        }
    }
}

安装与验证(OpenResty + LuaJIT)#

以 CentOS 7/8 为例,可替换为对应发行版仓库。

# 1) 安装依赖
yum install -y yum-utils gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel

# 2) 添加 OpenResty 仓库
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

# 3) 安装 OpenResty(含 LuaJIT)
yum install -y openresty

# 4) 启动并检查版本
/usr/local/openresty/nginx/sbin/nginx -v
/usr/local/openresty/bin/openresty -V
/usr/local/openresty/bin/luajit -v

验证示例:

# 载入配置并启动
/usr/local/openresty/nginx/sbin/nginx -t
/usr/local/openresty/nginx/sbin/nginx

# 访问测试
curl -i "http://127.0.0.1:8080/hello?name=ops"

预期输出:

HTTP/1.1 200 OK
Content-Type: text/plain

hello ops
count=1

关键命令解释#

  • nginx -t:检测配置语法,避免因语法错误导致启动失败。
  • nginx -s reload:平滑重载配置,不中断现有连接。
  • openresty -V:查看编译选项与模块,确认 ngx_lua 是否启用。
  • luajit -v:确认 LuaJIT 版本是否可用。

性能与稳定性注意事项(可操作)#

  • 避免阻塞:禁止在 content_by_lua 中执行 os.execute 或同步网络 I/O。
  • 共享缓存:使用 lua_shared_dict 保存计数与热点数据。
  • 代码热更新lua_code_cache on;(生产开启),开发调试可临时关闭。
  • 内存限制:共享字典大小不足会导致 no memory 错误。

排错清单(含命令)#

  1. 启动失败:unknown directive "content_by_lua_block"
    - 原因:未使用 OpenResty 或未编译 ngx_lua
    - 解决:
    bash /usr/local/openresty/bin/openresty -V | grep -i lua
  2. 访问 500:attempt to call global 'ngx' (a nil value)
    - 原因:在纯 Lua 环境执行了 ngx API
    - 解决:只在 Nginx/Lua 阶段执行脚本
  3. 共享字典不足:no memory
    - 解决:
    nginx lua_shared_dict metrics 50m;
  4. 热更新不生效
    - 原因:lua_code_cache on 缓存代码
    - 解决:开发环境临时关闭并 reload
    nginx lua_code_cache off;

练习任务#

  1. 限流练习:将 access_by_lua_block 改为 1 分钟内 20 次限流(使用 ngx.now() + shared dict 计数)。
  2. 鉴权练习:在 access_by_lua_block 中校验请求头 X-Token,失败返回 401。
  3. 日志练习:在 log_by_lua_block 中输出响应耗时 ngx.now() - ngx.req.start_time()

小结#

通过 LuaJIT 与 ngx_lua 的执行阶段、API 与配置方式,可以在 Nginx 内实现轻量级网关逻辑。结合安装、验证、排错和练习,可以快速形成可运行的开发与运维闭环。