了解 OpenResty XRay 是如何做到帮助企业定位应用程序存在的问题以及优化其效率的。

了解更多 LIVE DEMO

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

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

截图 1

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

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

截图 2

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

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

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

截图 4

一共需要 23 毫秒。

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

time resty -e ''

截图 6

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

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

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

截图 8

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

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

ls -lh *.ljbc

截图 10

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

然后再尝试用 resty 加载。

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

截图 12

总共只有 13 毫秒!

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

time resty -e ''

截图 14

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

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

mkdir conf logs lua

截图 16

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

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 的优化。
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"; }
    }
}

检查目录树。

tree .

截图 26

看起来不错!

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

time openresty -p $PWD/ -t

启动它。

time openresty -p $PWD/

截图 29

约 7 毫秒。

尝试删除 LuaJIT 字节码文件。

rm lua/*.ljbc

截图 31

停止服务器。

kill -QUIT `cat logs/nginx.pid`

截图 32

再次启动服务器。

time openresty -p $PWD/

截图 33

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

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

rm lua/*.lua

截图 35

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

time openresty -p $PWD/

截图 36

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

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

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

截图 38

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

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

截图 39

确实不多。但如果你有很多小模块要加载,节省的时间会很快积累起来。 如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

关于本文和关联视频

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

关于作者

章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

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