前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >遭遇lj_str_new

遭遇lj_str_new

作者头像
LA0WAN9
发布2021-12-14 09:04:26
3310
发布2021-12-14 09:04:26
举报
文章被收录于专栏:火丁笔记

话说前几天我刚通过 mlcache 优化了热数据的问题,屁股还没坐热乎呢,就发现系统性能又下降了,本着自己挖的坑含泪也要填上的原则,我再一次开始了性能调优之旅。

对某个 nginx 进程执行 perf top
对某个 nginx 进程执行 perf top

对某个 nginx 进程执行 perf top

毫无疑问,从 perf top 结果来看,lj_str_new 已经成为了性能最大的短板。不过我们还是要搞一个 lua 语言级别的火焰图看着才靠谱,于是有了下图:

优化前的火焰图
优化前的火焰图

优化前的火焰图

不出所料,lj_str_new 非常宽,不过没有更详细的调用栈信息,不方便判断问题到底出在哪,而且我的代码在优化前并没有遇到类似的问题,到底 lj_str_new 是什么玩意?还得从 lua 中的字符串说起,引自「如何编写正确且高效的 OpenResty 应用」:

Lua 跟其他大部分语言有一点不一样,就是它的字符串是不可变的。需要对实际的字符串内容做 hash,然后用它查找该内容是否已经创建了对应的实例。既然说到做 hash,那么自然得提到 hash 碰撞。对于那些 hash 值一样的字符串,LuaJIT 把它们存储在链表里。如果许多字符串有着一样的 hash 值,那么这个链表就会很长,原来 O(1) 的开销会退化为 O(n)。这就是所谓的 hash 碰撞。不幸的是,LuaJIT 的默认的字符串 hash 函数就有这样的问题。

看到这里,我已经猜到了问题的原因是我错误的使用了 mlcache,前面提到我通过 mlcache 优化了热数据的问题,实际上当时我为了多缓存一些数据,把 lru_size 设置为了一百万,可这一百万个 key 就是一百万个字符串啊,可想而知随着字符串越来越多,hash 碰撞就会越来越严重,也难怪火焰图中看不到 lj_str_new 详细的调用栈信息,因为任何一个字符串操作都可能有问题,系统性能必然下降。

解决方法很简单,把 lru_size 改小点儿,本例中我设置为 1000,只缓存最热的数据:

优化后的火焰图
优化后的火焰图

优化后的火焰图

仔细对比优化前后两张火焰图,你会发现 lj_str_new 几乎看不到了,收工。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档