关于lua_shared_dict的问题

634 views
Skip to first unread message

Ralin Yuan

unread,
Mar 25, 2015, 2:36:11 AM3/25/15
to open...@googlegroups.com

HiALL

        目前我们尝试使用lua_shared_dict作为业务数据的local cache作为一级缓存,看之前 @agentzh lua_shared_dict有过介绍https://groups.google.com/forum/#!topic/openresty/cDJeg2UqEF4

同时也提到过: lua_shared_dict通过紅黑树+自旋鎖来达成的当并发增大或是更新量增大时, 自旋鎖可能有问题”。我们的业务数据在lua_shared_dict只有插入、高频访问和LRU自动淘汰、没有更新操作,

因此不太确定是否lua_shared_dict适用于我们的业务场景。各位是否有这方面的使用经验?

Yichun Zhang (agentzh)

unread,
Mar 25, 2015, 3:12:21 PM3/25/15
to openresty
Hello!

2015-03-24 23:36 GMT-07:00 Ralin Yuan:
> 同时也提到过: “lua_shared_dict是通过紅黑树+自旋鎖来达成的,当并发增大或是更新量增大时,
> 自旋鎖可能有问题”。我们的业务数据在lua_shared_dict只有插入、高频访问和LRU自动淘汰、没有更新操作,
>
> 因此不太确定是否lua_shared_dict适用于我们的业务场景。各位是否有这方面的使用经验?
>

即使是较大的数据量(GB 级)和较多的 nginx worker
数(十几个),共享内存字典一般也不会成为真正的性能问题。最简单的验证方法是按照你们实际的数据量和访问模式进行 benchmark(同时使用
on-CPU 和 off-CPU 火焰图验证 benchmark 的结果,以避免低级错误)。

即使锁真的成为瓶颈,也可以通过对单个共享内存字典自己进行水平切分,在一个 nginx server 内部定义多个
lua_shared_dict 自己进行 hash 分发来规避。

Regards,
-agentzh

Ralin Yuan

unread,
Mar 25, 2015, 11:42:28 PM3/25/15
to open...@googlegroups.com
感谢 @agentzh 的答复,还有一个小疑问,lua_shared_dict是基于红黑树+自旋锁实现,看源码好像是每次set和get操作都会针对整棵树上锁,而不是基于插入的key的锁吧?
另外,我们在测试时发现,当内存写满后,再set时会存在有些失败的情况(ngx_slab_alloc() failed: no memory in lua_shared_dict zone),我们的统计:
1. 当memory未写满时,全部可以写入成功(包括大于page cache的元素,因此排除之前发现的nginx core的bug);
2. 写满再set,写入失败和写入成功的比例大概是1:2。
目前不太确定失败原因,我看到wiki上关于set操作的介绍 http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set,其中有一句:
When it fails to allocate memory for the current key-value item, then set will try removing existing items in the storage according to the Least-Recently Used (LRU) algorithm. Note that, LRU takes priority over expiration time here. If up to tens of existing items have been removed and the storage left is still insufficient (either due to the total capacity limit specified by lua_shared_dict or memory segmentation), then the err return value will be no memory and success will be false.

好像是说:当通过LRU去淘汰数据时,如果remove掉10个元素内存还是不够的话仍然会抛出 no memory的异常,想确认下我上面写入失败的原因是否可能是由于这个策略导致的呢?谢谢!

-----邮件原件-----
发件人: open...@googlegroups.com [mailto:open...@googlegroups.com] 代表 Yichun Zhang (agentzh)
发送时间: 2015年3月26日 3:12
收件人: openresty
主题: Re: [openresty] 关于lua_shared_dict的问题
--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@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

Ralin Yuan

unread,
Mar 26, 2015, 6:52:42 AM3/26/15
to open...@googlegroups.com
补充一下,关于lua_shared_dict在内存还充足的情况下写入失败的概率较大的问题,可能是由于nginx的slab内存分配存在碎片严重的问题,导致实际可用内存越来越小。参考:https://groups.google.com/forum/#!topic/openresty/9F9_OBtiA2E 这里的解决方案,在我的nginx 1.4.7上打上 https://raw.githubusercontent.com/openresty/ngx_openresty/master/patches/nginx-1.7.0-slab_defrag.patch
这个patch后,通过nginx-systemtap-toolkit查看总大小50m的内存,写满后free memory基本保持在3M左右,内存碎片的问题基本解决,同时写入失败的概率大幅下降至 2% 左右。
目前的遗留的问题是: 这2%的失败原因是否是由于移除多个元素后空间仍然不够导致的?如下描述中:
When it fails to allocate memory for the current key-value item, then set will try removing existing items in the storage according to the Least-Recently Used (LRU) algorithm. Note that, LRU takes priority over expiration time here. If up to tens of existing items have been removed and the storage left is still insufficient (either due to the total capacity limit specified by lua_shared_dict or memory segmentation), then the err return value will be no memory and success will be false.

谢谢!


-----邮件原件-----
发件人: open...@googlegroups.com [mailto:open...@googlegroups.com] 代表 Ralin Yuan
发送时间: 2015年3月26日 11:42
收件人: open...@googlegroups.com
主题: 答复: [openresty] 关于lua_shared_dict的问题

DeJiang Zhu

unread,
Mar 26, 2015, 10:58:29 AM3/26/15
to open...@googlegroups.com
在 2015年3月26日 上午11:42,Ralin Yuan <ralin...@hotmail.com>写道:
感谢 @agentzh 的答复,还有一个小疑问,lua_shared_dict是基于红黑树+自旋锁实现,看源码好像是每次set和get操作都会针对整棵树上锁,而不是基于插入的key的锁吧?

是的,一个 dict 一把大锁


好像是说:当通过LRU去淘汰数据时,如果remove掉10个元素内存还是不够的话仍然会抛出 no memory的异常,想确认下我上面写入失败的原因是否可能是由于这个策略导致的呢?谢谢!

不是 10 个,而是最多 30个 [1]

有可能的,如果你的数据大小差异很大的话
要验证的话,可以换成数据大小差不多的试一遍,春哥应该有更精确的办法


Yichun Zhang (agentzh)

unread,
Mar 26, 2015, 3:38:30 PM3/26/15
to openresty
Hello!

2015-03-25 20:42 GMT-07:00 Ralin Yuan:
> 感谢 @agentzh 的答复,还有一个小疑问,lua_shared_dict是基于红黑树+自旋锁实现,看源码好像是每次set和get操作都会针对整棵树上锁,而不是基于插入的key的锁吧?

是的,红黑树经常需要 rebalance,所以是整树锁。

> 另外,我们在测试时发现,当内存写满后,再set时会存在有些失败的情况(ngx_slab_alloc() failed: no memory in lua_shared_dict zone),

你在日志里面看到的”ngx_slab_alloc() failed: no memory in lua_shared_dict
zone”这条消息是 error 级别的是还是 info 级别的?如果是 info
级别的则完全可以忽略,因为根本不是错误。在空闲空间消耗尽之后,shared dict 自动按 LRU 踢除现有的元素。

你应当只对 set() 方法的返回值在 Lua 层面上进行恰当的错误处理(比如在 set 返回错误时自动重试一次或多次)。不应对日志消息过于敏感。

> 好像是说:当通过LRU去淘汰数据时,如果remove掉10个元素内存还是不够的话仍然会抛出 no memory的异常,想确认下我上面写入失败的原因是否可能是由于这个策略导致的呢?谢谢!
>

正如上面所指出的,你应当确认 set() 是否真的失败(即检查 set 的返回值)。而且即使 set() 真的返回了失败,重试多次也会最终成功。

> 补充一下,关于lua_shared_dict在内存还充足的情况下写入失败的概率较大的问题,
> 可能是由于nginx的slab内存分配存在碎片严重的问题,导致实际可用内存越来越小。
> 参考:https://groups.google.com/forum/#!topic/openresty/9F9_OBtiA2E 这里的解决方
> 案,在我的nginx 1.4.7上打上

这个问题已经在官方较新的 nginx 核心中修复了。你为什么不直接升级 nginx
核心呢?另外,值得一提的是,为避免不必要的麻烦,建议总是使用最新的 OpenResty 软件包:

http://openresty.org/#Download

Regards,
-agentzh

Ralin Yuan

unread,
Mar 26, 2015, 11:31:13 PM3/26/15
to open...@googlegroups.com
> 你应当只对 set() 方法的返回值在 Lua 层面上进行恰当的错误处理(比如在 set 返回错误时自动重试一次或多次)。不应对日志消息过于敏感。
是的,接下来考虑增加重试一次的逻辑,提高set的成功率。另外纠正我之前的错误,如 @ DeJiang Zhu 所说,通过LRU去淘汰数据时,最多会remove掉30个元素,不是最多10个。
>这个问题已经在官方较新的 nginx 核心中修复了。你为什么不直接升级 nginx核心呢?
因为目前还依赖 taobao的nginx-tfs模块,该模块目前只能运行在最高 1.4的nginx版本上,因此没有升级nginx核心到最高版本。

最后一并感谢 @agentzh 和 @ DeJiang Zhu 两位!





-----邮件原件-----
发件人: open...@googlegroups.com [mailto:open...@googlegroups.com] 代表 Yichun Zhang (agentzh)
发送时间: 2015年3月27日 3:38
收件人: openresty
主题: Re: 答复: [openresty] 关于lua_shared_dict的问题

Yichun Zhang (agentzh)

unread,
Mar 27, 2015, 3:27:38 PM3/27/15
to openresty
Hello!

2015-03-26 20:31 GMT-07:00 Ralin Yuan:
> 因为目前还依赖 taobao的nginx-tfs模块,该模块目前只能运行在最高 1.4的nginx版本上,因此没有升级nginx核心到最高版本。
>

这个要命啊,nginx 1.4 中有很多已知的 bug 都先后在后续的版本中修复了(其中我就贡献了好多个 patch)。

Regards,
-agentzh

Ralin Yuan

unread,
Mar 29, 2015, 10:22:19 PM3/29/15
to open...@googlegroups.com
> 这个要命啊,nginx 1.4 中有很多已知的 bug 都先后在后续的版本中修复了(其中我就贡献了好多个 patch)。

@agentzh, tfs这个模块确实难办,如果升级不了核心,是不是只能把补丁都打一遍?

-----邮件原件-----
发件人: open...@googlegroups.com [mailto:open...@googlegroups.com] 代表 Yichun Zhang (agentzh)
发送时间: 2015年3月28日 3:28
收件人: openresty
主题: Re: 答复: 答复: [openresty] 关于lua_shared_dict的问题

Yichun Zhang (agentzh)

unread,
Mar 30, 2015, 5:35:41 PM3/30/15
to openresty
Hello!

2015-03-29 19:22 GMT-07:00 Ralin Yuan:
>
> @agentzh, tfs这个模块确实难办,如果升级不了核心,是不是只能把补丁都打一遍?
>

这可不容易,很容易引入新的问题,特别是当你不够了解 nginx 核心的时候(不过如果你足够了解 nginx 了,应当也不难让那个 tfs
模块兼容新的 nginx core)。

Regards,
-agentzh
Reply all
Reply to author
Forward
0 new messages