NJet深层清理Lua代码

简介

NJet 集成了Lua 的运行环境,在不配置 lua_code_cache off; 的情况下,worker收到请求时,会从context中获取已经创建的Lua VM (第一次执行Lua相关代码时创建)。Lua VM中, package.loaded 是一个核心的 Lua 表,它扮演着 Lua 模块缓存的角色。当使用 require("module_name") 加载一个 Lua 模块时,Lua 解释器会首先检查 package.loaded 表中是否已经存在名为 module_name 的模块。如果存在,它会直接返回已缓存的模块值;如果不存在,它才会去文件系统(根据 package.path)查找、加载并执行该模块文件,然后将其返回值存储到 package.loaded 中,供后续调用。

在配置了多个 worker 进程时, 每个worker 进程都拥有自己独立的 LuaJIT 虚拟机实例 (Lua State)。这意味着每个 worker 进程的 Lua 虚拟机都有自己独立的 package.loaded 表,它们之间互不影响。有可能造成部分worker进程缓存了模块,部分进程没有对模块进行缓存。

当更新了磁盘上的 Lua 模块文件时,例如 mylib.lua, package.loaded 中已经缓存了旧版本的 mylib的worker进程将执行旧版的代码,而未缓存该模块的部分worker进程收到请求时将直接使用新版本,这样照成了各个worker的行为不一致。并且那些被间接 require 的模块(即主 Lua 脚本 require 了 A,而 A 又 require 了 B),Lua 自身也没有机制去追踪这种深层次的依赖关系并自动刷新。

动态清除方案

NJet提供了完善的动态配置框架,通过NJet Copilot提供的消息机制,使用控制面提供的Restful API可以对进行了动态改造的模块进行实时的配置修改,而不需要触发配置文件的全量重加载或重启。

使用相同的动态配置机制,NJet 解决了上文提及的模块缓存清除问题。NJet 控制面提供了配置URL "/api/v1/config/http_lua_package_clean" (需要加载http动态lua模块 njt_http_dyn_lua_module.so, 将需要清除缓存的模块名称,使用JSON 的字符串数据 PUT 到该接口,所有Worker 进程 Lua VM的package.loaded 表中,都将会把数组中列出的所有模块名进行清理。例如:

rust 复制代码
curl -X 'PUT' -d '["mylib", "mylib.util", "mylib.common"]' 'http://localhost:8081/api/v1/config/http_lua_package_clean' 

NJet 内置的swagger 文档也进行了相应的更新,可以通过swagger 提供的页面在浏览器中进行修改。

测试验证

Njet 中加载lua 及动态lua 模块,并配置一个静态 location

ini 复制代码
helper ctrl /usr/local/njet/modules/njt_helper_ctrl_module.so /usr/local/njet/conf/njet_ctrl.conf;
helper broker /usr/local/njet/modules/njt_helper_broker_module.so conf/mqtt.conf;
load_module /usr/local/njet/modules/njt_http_lua_module.so;
load_module /usr/local/njet/modules/njt_http_dyn_lua_module.so;

worker_processes auto;
cluster_name njet;
node_name node1;
error_log logs/error.log info;
events {
    worker_connections  1024;
}

http {
    include mime.types;
    lua_package_path "$prefix/lualib/lib/?.lua;/usr/local/njet/modules/?.lua;$prefix/apps/?.lua;;";
    lua_package_cpath "$prefix/lualib/clib/?.so;;";

    server {
        listen       80;
        location / {
           root html;
        }
       
        location /luatest {
           content_by_lua_block {
              local mylib = require("mylib")
               mylib.run()
           }
        }
   }

/luatest 中调用了mylib包中的 run函数, mylilb.lua 放在 lua_package_path 指定的其中一个路径中,如 $prefix/apps/

lua 复制代码
local _M={}

function _M.run()
   njt.say("in mylib, init version")
end

return _M

访问 /luatest

使用动态lua, 修改 /luatest 中的 content_by_lua_block 内容

vbnet 复制代码
curl -X 'PUT' \
  'http://localhost:8081/api/v1/config/http_lua' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "servers": [
    {
      "listens": [
        "0.0.0.0:80"
      ],
      "serverNames": [
        ""
      ],
      "locations": [
        {
          "location": "/",
          "lua": {}
        },
        {
          "location": "/luatest",
          "lua": {
            "content_by": " njt.say("before mylib run")  \n  local mylib = require("mylib")\n  mylib.run()\n  njt.say("after mylib run")      "
          }
        }
      ]
    }
  ]
}'

同时修改 mylib.lua

lua 复制代码
local _M={}

function _M.run()
   njt.say("in mylib, here is the updated version")
end

return _M

再次访问 /luatest, 动态lua 的改动已生效,但是引用的 package 改动不生效

使用 NJet控制面提供的lua package缓存清除机制

说明

  • NJet v3.3.1 版本开始支持该API
  • 模块名称与文件路径关系是Lua的标准机制,在配置的package_path中依次搜索,将点号(.)替换为目录分隔符, 添加.lua扩展名,require("a.b") 会查找 搜索路径下的 a/b.lua
相关推荐
岁岁种桃花儿7 小时前
详解 Kubernetes 命令:kubectl exec -it nginx -- bash 及实战场景
运维·nginx·kubernetes
VueVirtuoso7 小时前
前后端部署 + Nginx 配置 + Cloudflare 全攻略(通俗易懂版)
运维·nginx
小白银子7 小时前
零基础从头教学Linux(Day 42)
linux·运维·服务器·网络·nginx
初学者_xuan8 小时前
零基础新手小白快速了解掌握服务集群与自动化运维(七)Nginx模块--Nginx反向代理与缓存功能(二)
运维·nginx·自动化
看好多桂花树8 小时前
Nginx SSL/TLS 配置
网络·nginx·ssl
岚天start8 小时前
Nginx配置中location和proxy_pass指令尾部是否带斜杠的区别
运维·nginx·centos·proxy_pass·location·uri·斜杠
xx.ii8 小时前
54.Nginx部署与lnmp的部署
运维·nginx·负载均衡
用户516816614584111 小时前
使用[DeepSeek]快速定位nginx前端部署后报错:500 Internal Server Error nginx/1.29.1
nginx·deepseek
宁雨桥13 小时前
Nginx反向代理配置全流程实战:从环境搭建到HTTPS部署
运维·nginx·https
花开富贵贼富贵13 小时前
Nginx 配置指南:HTTPS 自签名、Location、Rewrite 与状态统计
运维·nginx·https