ngx.re 性能比 lua 内置正则函数还差?

703 views
Skip to first unread message

xfwang...@gmail.com

unread,
Apr 19, 2017, 5:47:18 AM4/19/17
to openresty
大家好,

根据这个最佳实践 https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/re.html,建议使用 ngx.re 替代 lua 内置正则,想来也是,既然 openresty 自己实现了,应该比 lua 好才对, 但是简单测试之后发现,ngx.re 比 lua 正则还差,函运行时间差了大概 5 倍,下面是简单循环调用了 100 W 次的结果:

ngx.re.gmatch-oji: 1.9860000610352s
ngx.re.gmatch-i: 3.2929999828339s
string.gmatch: 0.48600006103516s

测试数据:
ngx.re.gmatch("a:100.00,b:200.00,c:300.00", "(\\w+):([+-]?\\d+.\\d+)", "ioj")
string.gmatch("a:100.00,b:200.00,c:300.00", "(\\w+):([+-]?\\d+.\\d+)", "i")

另外,通过 --with-debug 查看日志,发现打印 pcre JIT compiling result: 0,如果根据 https://github.com/openresty/lua-nginx-module#ngxrematch 应该是 1 才是启用了 pcre jit,但通过前后日志好像已经命中了缓存了:

2017/04/19 16:47:23 [debug] 31321#0: *3 lua access handler, uri:"/bench_misc" c:1
2017/04/19 16:47:23 [debug] 31321#0: *3 post access phase: 11
2017/04/19 16:47:23 [debug] 31321#0: *3 lua content handler, uri:"/bench_misc" c:1
2017/04/19 16:47:23 [debug] 31321#0: *3 posix_memalign: 0000000001BCD8F0:4096 @16
2017/04/19 16:47:23 [debug] 31321#0: *3 lua reset ctx
2017/04/19 16:47:23 [debug] 31321#0: *3 lua creating new thread
2017/04/19 16:47:23 [debug] 31321#0: *3 http cleanup add: 0000000001B78E90
2017/04/19 16:47:23 [debug] 31321#0: *3 lua run thread, top:0 c:1
2017/04/19 16:47:23 [debug] 31321#0: *3 lua regex cache miss for match regex "(\w+):([+-]?\d+.\d+)" with options "oji"
2017/04/19 16:47:23 [debug] 31321#0: *3 lua compiling gmatch regex "(\w+):([+-]?\d+.\d+)" with options "oji" (compile once: 1) (dfa mode: 0) (jit mode: 1)
2017/04/19 16:47:23 [debug] 31321#0: *3 pcre JIT compiling result: 0
2017/04/19 16:47:23 [debug] 31321#0: *3 lua saving compiled regex (2 captures) into the cache (entries 0)
2017/04/19 16:47:23 [debug] 31321#0: *3 lua regex cache hit for match regex "(\w+):([+-]?\d+.\d+)" with options "oji"
2017/04/19 16:47:23 [debug] 31321#0: *3 lua regex cache hit for match regex "(\w+):([+-]?\d+.\d+)" with options "oji"
2017/04/19 16:47:23 [debug] 31321#0: *3 lua regex cache hit for match regex "(\w+):([+-]?\d+.\d+)" with options "oji"
2017/04/19 16:47:23 [debug] 31321#0: *3 lua allocate new chainlink and new buf of size 22, cl:0000000001B78EC8

大家有什么建议?

FQ Liu

unread,
Apr 19, 2017, 6:00:18 AM4/19/17
to openresty
1. 你测试时起码要检查你写的代码产生了正常的结果。 string.gmatch()返回一个迭代器,本身没有执行任何匹配操作。
2. 你传递给string.gmatch的参数根本就不对。
3. string.gmatch只实现了简单的匹配,没有支持很多的正则特性

在 2017年4月19日星期三 UTC+8下午5:47:18,xfwang...@gmail.com写道:

xfwang...@gmail.com

unread,
Apr 19, 2017, 6:15:01 AM4/19/17
to openresty
1. 两者都是迭代器,肯定访问迭代器了,并取得了正确结果
2  string.gmatch("a:100.00,b:200.00,c:300.00", "(\\w+):([+-]?\\d+.\\d+)", "i")  这是线上的代码,结果完全正确
3. 据说 ngx.re 更好,所以准备升级,但是一压测性能更差,至于特性,string.match 目前完全够用,在功能一样的情况下,肯定选用性能更好的

xfwang...@gmail.com

unread,
Apr 19, 2017, 6:28:29 AM4/19/17
to openresty
不好意思,贴错了两次string.match 应该是  string.gmatch("p:100.00,tpp:200.00,sp:300.00", "(%w+):([+-]?%d+.?%d+)")
确实是发现 ngx.re 性能更差,

另外线上跑的是 1.7.2.1 版本,比较老了,直接下了最新的 1.11.2.2,但是发现同样的代码,不仅没有提升,还下降了一些,

Yuansheng Wang

unread,
Apr 19, 2017, 6:38:28 AM4/19/17
to open...@googlegroups.com
2017-04-19 18:15 GMT+08:00 <xfwang...@gmail.com>:
1. 两者都是迭代器,肯定访问迭代器了,并取得了正确结果
2  string.gmatch("a:100.00,b:200.00,c:300.00", "(\\w+):([+-]?\\d+.\\d+)", "i")  这是线上的代码,结果完全正确
3. 据说 ngx.re 更好,所以准备升级,但是一压测性能更差,至于特性,string.match 目前完全够用,在功能一样的情况下,肯定选用性能更好的

  1. ngx.re.gmatch 需要 local 缓存一下,否则很多时间浪费在找 gmatch 函数上
  2. 如果你们这里对正则性能有要求,还需要注意一下 ngx.re.gmatch 的最后一个 ctx 参数,

对于这种性能问题,最好用火焰图照一下,看看所有时间都被消耗到什么地方。
 

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty+subscribe@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+unsubscribe@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html



--

membphis

xfwang...@gmail.com

unread,
Apr 19, 2017, 9:00:05 AM4/19/17
to openresty
1. 我们所有函数,包括 *.gmatch 都是 local 缓存的,另外我们也发现 local 函数在 luajit 下其实性能提升微乎其微
2. gmatch 函数没有 ctx 参数, match 才有
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com



--

membphis

FQ Liu

unread,
Apr 19, 2017, 10:02:11 AM4/19/17
to openresty
1. 测了下,ngx.re.gmatch确实与string.gmatch相比需要4-5倍的时间处理。个人猜测主要是ngx.re.gmatch每次都要新建字符串在缓存中查找,消耗比较大
2. pcre JIT compiling result: 0 这个可能是编译pcre库的时候没有开启jit的支持,编译pcre时可以通过./configure --enable-jit开启

在 2017年4月19日星期三 UTC+8下午9:00:05,xfwang...@gmail.com写道:

xfwang...@gmail.com

unread,
Apr 19, 2017, 12:07:56 PM4/19/17
to openresty
pcre 这个根据日志应该是命中缓存了,我没有单独源码编译 pcre,暂时不管它了

性能这个只有眼见为实,刚接手 ngx+lua 项目,准备优化下,按网上各种说法,很多都提升不明显(例如 table.insert 换 table[#table+1],使用 local 先引用全局函数,使用 for i=1, #table 替代 ipair 等等),一不小心还降低了

另外,我还尝试升级了版本,从 1.7.2.1 到 1.11.2.2,结果吞吐量掉了快 20%,功能越来越强大,牺牲了性能,伤心死了 :)

版本跳跃太大,也不知道哪里开销大了,也不知道是 nginx 的问题还是 lua-ngx 模块的问题了, 可能得试试中间版本例如 1.9,不知大家有什么经验没有?

Zexuan Luo

unread,
Apr 19, 2017, 10:33:22 PM4/19/17
to openresty
如果系统自带的 pcre 版本过低,单独源码编译 pcre 是非常值得的。经过 jit 之后的性能会有明显的提升。
另外可以尝试 require 'resty.core.regex',之前观察到某些情况下用基于 ffi 的 ngx.re 会快一些。


当然这些只是经验之谈。科学的办法,是各用 ngx.re.gmatch 和 string.gmatch 压火焰图(Lua栈 和 C栈),然后我们再对着火焰图谈一谈瓶颈在哪、怎么优化。
 

在 2017年4月20日星期四 UTC+8上午12:07:56,xfwang...@gmail.com写道:

xfwang...@gmail.com

unread,
Apr 19, 2017, 11:57:07 PM4/19/17
to openresty
火焰图回头有时间会照一下,

resty.core.regex 这个模块应该是默认编译进去吧,直接替代了原来 C 的实现了吧,直接调用了 ngx.re.* 接口就可以了吧?根据文档并没有找到单独的 api 啊, https://github.com/openresty/lua-resty-core#restycoreregex 

Zexuan Luo

unread,
Apr 20, 2017, 4:30:08 AM4/20/17
to open...@googlegroups.com
直接 require "resty.core.regex" 即可。比如在 init_by_lua_block 里面加一行:
init_by_lua_block {
        require "resty.core.regex"
        ...
}

订阅: 请发空白邮件到 openresty+subscribe@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+unsubscribe@googlegroups.com
Reply all
Reply to author
Forward
0 new messages