本教程演示了在 OpenResty 中对用户 Lua 代码进行基准测试的正确方法和错误方法。

1
2
3
cd ~
mkdir time-lua
cd time-lua/

首先,要保证我们的 CPU 始终处于全速运转状态。

1
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

截图 2

它通常默认取值 powersave 而我们需要设置成 performance

对一些 Lua 代码进行计时的最简单方法是使用 time 命令和 resty 命令。

1
time resty -e 'ngx.re.find("hello, world.", [[\w+\.]], "jo")'

截图 4

但这种方法有一个问题。resty命令本身有一个启动和退出的开销。

1
time resty -e ''

截图 6

我们可以看到在这台机器上的开销大约有 11 毫秒。

相反,我们应该使用 OpenResty 提供的ngx.now Lua API函数。

1
restydoc -s ngx.now

截图 8

让我们把我们的 Lua 代码放到一个名为 ./bench.lua 的文件中,以便更好地阅读。

我们进行以下编辑:

  1. 首先,我们要确保 nginx 里面的缓存时间是最新的。
  2. 然后我们记录的开始时间有毫秒的精度。
  3. 然后把我们前面提到的正则匹配调用。
  4. 然后我们再更新缓存时间。
  5. 最后,通过做时间减法输出经过的时间。
  6. 让我们保存文件。
1
2
3
4
5
ngx.update_time()
local begin = ngx.now()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
ngx.update_time()
ngx.say("elapsed seconds: ", ngx.now() - begin)

截图 15

然后运行 resty 这个 shell 命令。

1
resty bench.lua

截图 18

它记录的延迟时间大约是 1 毫秒。但我们很快就会发现它很不准确。

正确的方法是在 bench.lua 文件中做如下编辑:

  1. 把调用放到一个名为 target 的 Lua 函数中。
  2. 然后先调用这个函数 100 次作为热身。现在这个 target 函数应该在这个循环执行完后进行 JIT 编译。
  3. 然后在定时码区域里面,我们反复调用 1000 万次。
  4. 最后我们计算平均时间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end

for i = 1, 100 do
target()
end

ngx.update_time()
local begin = ngx.now()

local N = 1e7
for i = 1, N do
target()
end

ngx.update_time()
ngx.say("elapsed: ", (ngx.now() - begin) / N)

截图 25

我们现在再次运行这个脚本。

1
resty bench.lua

截图 26

我们可以看到,每次调用仅仅是 30 纳秒左右。比之前的结果快了很多很多倍!

实际上,我们可以进一步确保在我们给代码计时之前,没有死掉的 GC 对象还没有被回收,只要在第一个 ngx.update_time() 调用之前插入以下一行代码。只需在第一个 ngx.update_time() 调用之前插入以下一行代码。

1
collectgarbage()

截图 29

在这里,我们强制执行一个完整的 GC 周期,然后再记录开始时间。

但是,它对我们这里的例子没有什么帮助。这是因为我们的定时代码无论如何也不会创建很多 GC 对象。

我们可以通过避免不必要的 Lua 表查找操作,使 target 函数更快。

1
2
3
4
5
local re_find = ngx.re.find

local function target()
re_find("hello, world.", [[\w+\.]], "jo")
end

截图 33

但这里的差别可能比较小。

截图 35

这就是我今天要讲的内容。希望你觉得有趣。 如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

关于本文和关联视频

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

关于作者

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

关注我们

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

我们的微信公众号

翻译

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