Skip to content

Latest commit

 

History

History
142 lines (91 loc) · 7.33 KB

init_by_lua.md

File metadata and controls

142 lines (91 loc) · 7.33 KB

init_by_lua

语法: init_by_lua <lua-script-str>

环境: http

阶段: loading-config

当Nginx master进程(如果有)加载Nginx配置文件时,在全局的Lua虚拟机上运行<lua-script-str>指定的Lua代码。

当Nginx收到HUP信号并开始重新加载配置文件,Lua虚拟机将重新创建并且init_by_lua在新的Lua虚拟机中再次执行。为防止lua_code_cache指令是关闭的(默认打开),对于这个场景init_by_lua将在每个请求之上运行,因为在这个场景中,每个请求都会创建新的Lua虚拟机,他们都是独立存在。

通常,你可以在服务启动时注册Lua全局变量或预加载Lua模块。这是个预加载Lua模块的示例代码:

 init_by_lua 'cjson = require "cjson"';

 server {
     location = /api {
         content_by_lua '
             ngx.say(cjson.encode({dog = 5, cat = 6}))
         ';
     }
 }

你也可以在这个阶段初始化lua_shared_dict共享内存内容。这里是示例代码:

 lua_shared_dict dogs 1m;

 init_by_lua '
     local dogs = ngx.shared.dogs;
     dogs:set("Tom", 56)
 ';

 server {
     location = /api {
         content_by_lua '
             local dogs = ngx.shared.dogs;
             ngx.say(dogs:get("Tom"))
         ';
     }
 }

需要注意,当配置重载(例如HUP信号)时lua_shared_dict的共享数据是不会被清空。这种情况下,如果你不想在init_by_lua再次再初始化你的共享数据,你需要设置一个个性标识并且在你的init_by_lua代码中每次都做检查。

因为在这个指令的Lua代码执行是在Nginx fork他的工作进程(如果有),加载的数据和代码将被友好Copy-on-write (COW)特性提供给其他所有工作进程,从而节省了大量内存。

不要在这个上下文中初始化你自己的Lua全局变量,因为全局变量的使用有性能损失并会带来全局命名污染(可以查看Lua 变量范围获取更多细节)。推荐的方式是正确使用Lua模块 文件(不要使用标准Lua函数module()来定义Lua模块,因为它同样对全局命名空间有污染),在init_by_lua 或 其他上下文中调用require()来加载你自己的模块文件。require()会在全局Lua注册的package.loaded表中缓存Lua模块,所以在整个Lua虚拟机实例中你的模块将只会加载一次。

在这个上下文中,只有一小部分的Nginx Lua API是被支持的:

在这个上下文中,根据用户的后续需要,将会支持更多的Nginx Lua APIs。

基本上,在这个上下文中,你可以保守使用Lua库完成阻塞I/O调用,因为在master进程的阻塞调用在服务的启动过程中是完全没问题的。进一步说在配置加载阶段,Nginx核心就是阻塞 I/O 方式处理的(至少在解析上游主机名称时)。

你应该非常小心,在这种情况下注册的Lua代码潜在的安全漏洞,因为Nginx的主进程经常是'root`帐户下运行。

这个指令是v0.5.5版本中第一次引入的。

返回目录

English source:

init_by_lua

syntax: init_by_lua <lua-script-str>

context: http

phase: loading-config

Runs the Lua code specified by the argument <lua-script-str> on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.

When Nginx receives the HUP signal and starts reloading the config file, the Lua VM will also be re-created and init_by_lua will run again on the new Lua VM. In case that the lua_code_cache directive is turned off (default on), the init_by_lua handler will run upon every request because in this special mode a standalone Lua VM is always created for each request.

Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules:

 init_by_lua 'cjson = require "cjson"';

 server {
     location = /api {
         content_by_lua '
             ngx.say(cjson.encode({dog = 5, cat = 6}))
         ';
     }
 }

You can also initialize the lua_shared_dict shm storage at this phase. Here is an example for this:

 lua_shared_dict dogs 1m;

 init_by_lua '
     local dogs = ngx.shared.dogs;
     dogs:set("Tom", 56)
 ';

 server {
     location = /api {
         content_by_lua '
             local dogs = ngx.shared.dogs;
             ngx.say(dogs:get("Tom"))
         ';
     }
 }

But note that, the lua_shared_dict's shm storage will not be cleared through a config reload (via the HUP signal, for example). So if you do not want to re-initialize the shm storage in your init_by_lua code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your init_by_lua code.

Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the Copy-on-write (COW) feature provided by many operating systems among all the worker processes, thus saving a lot of memory.

Do not initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the Lua Variable Scope section for more details). The recommended way is to use proper Lua module files (but do not use the standard Lua function module() to define Lua modules because it pollutes the global namespace as well) and call require() to load your own module files in init_by_lua or other contexts (require() does cache the loaded Lua modules in the global package.loaded table in the Lua registry so your modules will only loaded once for the whole Lua VM instance).

Only a small set of the Nginx API for Lua is supported in this context:

More Nginx APIs for Lua may be supported in this context upon future user requests.

Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase.

You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the root account.

This directive was first introduced in the v0.5.5 release.

Back to TOC