Hello!
2016-09-24 18:48 GMT-07:00 Yun Thanatos <yunth...@gmail.com>:
>>> (gdb) bt
>>> #0 sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
>>> #1 0x0000000000421d4c in ngx_shmtx_lock (mtx=0x7ff337ab6050) at
>>> src/core/ngx_shmtx.c:142
>>> #2 0x00000000004bf6b7 in ngx_http_lua_shdict_set_helper
>>> (L=L@entry=0x41cd7598, flags=flags@entry=0)
>>> at addon/lua-nginx-module-0.9.17/src/ngx_http_lua_shdict.c:952
>>> #3 0x00000000004bfee3 in ngx_http_lua_shdict_delete (L=0x41cd7598) at
>>> addon/lua-nginx-module-0.9.17/src/ngx_http_lua_shdict.c:586
>>> #4 0x00000000004f7bcb in lj_BC_FUNCC ()
>>> #5 0x00000000004f9e8b in gc_call_finalizer ()
>>> #6 0x00000000004f9fc4 in gc_finalize ()
>>> #7 0x00000000004fab1f in gc_onestep ()
>>> #8 0x00000000004fafcc in lj_gc_step ()
>>> #9 0x00000000004e6ac3 in lua_pushlstring ()
OK,谜题解开了,是因为你自己的 Lua 代码(或者你使用的第三方 Lua 代码)里在 gc handler 里面调用了
shdict:delete() 方法,这会导致死锁,因为 GC handler 有可能会在 shdict
的方法调用内部触发,而在持有锁的情况下,再进入一个嵌套的 shdict 方法调用,尝试拿锁,自然是永远拿不到的。你可以使用 lbt 命令取得
Lua 调用栈关系,看看是你使用的什么位置的 Lua 代码在 GC 函数里调用了 shdict:delete() 方法。
当然,还有一种解决方法是使用 lua-resty-core 库,即在nginx.conf 的 http {} 里添加下面这段配置:
init_by_lua_block { require "resty.core" }
lua-resty-core 库里的 shdict API 实现是基于 FFI 的,所以不会在持有 shmtx 锁的情况下触发 Lua VM
的 GC step,从而不会产生你看到的死锁问题。
Regards,
-agentzh