本教程演示了如何将 Lua 模块预编译成 LuaJIT 字节码。这可以帮助减少OpenResty应用程序的启动时间。

1
2
3
4
export PATH=/usr/local/openresty/bin:$PATH
cd ~
mkdir -p precomp
cd precomp/

截图1

这里我们将使用一个大的Lua模块文件pkg-stap.lua。它是由我们的 opslang 编译器生成的。

1
2
cp ~/git/opslang/pkg-stap.lua ./
ls -lh *.lua

截图2

我们可以看到,这个Lua模块是1.6MB。

让我们尝试用resty工具加载这个Lua模块。

1
time resty -I. -e 'require "pkg-stap"'

截图4

一共需要23毫秒。

让我们检查一下运行一个空的Lua程序的原始开销。

1
time resty -e ''

截图6

大约是11毫秒。所以加载模块本身大约需要12毫秒。

让我们尝试将Lua模块预编译成LuaJIT字节码。

1
time /usr/local/openresty/luajit/bin/luajit -bg pkg-stap.lua pkg-stap.ljbc

截图8

这里我们使用OpenResty的luajit程序。

它生成一个LuaJIT字节码文件,文件扩展名为.ljbc

1
ls -lh *.ljbc

截图10

看到字节码文件也小了50%以上,很有意思!

然后再尝试用resty加载。

1
time resty -I. -e 'require "pkg-stap"'

截图12

总共只有13毫秒!

现在几乎就像加载一个空的Lua程序一样!只多了2毫秒。

1
time resty -e ''

截图14

当加载一个模块时,"resty “工具总是试图在”.lua “文件之前加载一个”.ljbc "文件。

让我们看看如何让它在OpenResty服务器上工作。

1
mkdir conf logs lua

截图16

将我们的Lua模块文件复制到lua/子目录下。

1
2
mv *.lua *.ljbc lua/
tree .

截图17

写一个简单的nginx配置文件,conf/nginx.conf。我们做如下编辑。

  1. 启用单个 nginx 工作进程。
  2. 使用1024个每工作进程的连接。
  3. lua_package_path指令中,重要的是要在.lua文件之前尝试.ljbc文件。你也可以尝试只保留.ljbc文件来确定。
  4. 在 "init_by_lua_block "中,我们预先加载了我们的模块,这样任何模块加载失败都可以在服务器启动时被发现。这也导致了更快的首次请求和更小的内存占用,这是因为COW的优化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
worker_processes 1;

events {
worker_connections 1024;
}

http {
lua_package_path "$prefix/lua/?.ljbc;$prefix/lua/?.lua;;";

init_by_lua_block {
require "pkg-stap"
}

server {
listen 8080;
location / { return 200 "ok\n"; }
}
}

检查目录树。

1
tree .

截图26

看起来不错!

尝试使用-t选项测试服务器配置。

1
time openresty -p $PWD/ -t

启动它。

1
time openresty -p $PWD/

截图29

约7毫秒。

尝试删除LuaJIT字节码文件。

1
rm lua/*.ljbc

截图31

停止服务器。

1
kill -QUIT `cat logs/nginx.pid`

截图32

再次启动服务器。

1
time openresty -p $PWD/

截图33

这次是17毫秒!我们可以通过加载Lua源文件看到它也慢了10毫秒。

最后,也可以尝试删除Lua源文件。

1
rm lua/*.lua

截图35

停止服务器并重新启动它。

1
time openresty -p $PWD/

截图36

这一次,我们得到了一个预期的错误,因为两个版本的模块都不见了。

对于小的Lua模块文件,加载它们的源代码已经非常快了。

1
2
3
echo 'local _M = {} function _M.foo() end return _M' > a.lua
ls -l a.lua
time resty -I. -e 'require "a"'

截图38

预编译一个小的Lua模块文件不会有太大的帮助。

1
2
time /usr/local/openresty/luajit/bin/luajit -bg a.lua a.ljbc
time resty -I. -e 'require "a"'

截图39

确实不多。但如果你有很多小模块要加载,节省的时间会很快积累起来。

如果你喜欢这个视频,请订阅我们的 YouTube 频道B 站频道。谢谢!

关于本文和关联视频

本文和相关联的视频都是完全由我们的 OpenResty Demo 系统从一个极简单的剧本文件自动生成的。

关于作者

章亦春是开源项目 OpenResty® 的创始人,同时也是 OpenResty Inc. 公司的创始人和 CEO。他贡献了许多 Nginx 的第三方模块,相当多 Nginx 和 LuaJIT 核心补丁,并且设计了 OpenResty XRay 等产品。

关注我们

如果您觉得本文有价值,非常欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文) 。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!