起因是需要更多的控制 nginx 的行为,就目前已经实现的 phase 对于 upstream 控制并不怎么方便,尝试一些办法之后,想到了一个方法,就是 set_by_lua+map 指令组合起来的方案,对于 nginx 本身几乎没有任何修订。
基于这个想法实现一个新的 phase 叫做 map_by_lua,借助 nginx 的变量系统,这个 phase 可以在任意的 nginx 变量求值上下文环境中执行一段 lua 代码,只要支持变量都可以通过这个 phase 注入一段 lua 代码,以便获得准确的执行时机。
与 set_by_lua 的不同点在于,它是在求值的时候执行的。
在测试的时候出现了一个棘手的问题,因为是惰性求值,就会出现递归调用的情况:
map_by_lua_block $m {
return ngx.var.host
}
map_by_lua_block $mapby {
return ngx.var.m
}
lua_load_resty_core on;
server {
add_header mapby $mapby;
}
这种调用方式会使 worker 崩溃。经过多次测试,发现只要开启 resty.core 之后就会出现问题,也是因为开启之后 ngx.var.API 变成了 FFI 实现版本,不再是 Lua C API 版本。目前测试情况是,Lua C API 版本不出现问题。另外,FFI 版本访问的不是这个 phase 定义的 nginx 变量也没有问题。
所以这个问题有点搞不明白,是因为 FFI 就不能再次调用 lua_pcall 执行一段 lua 代码?还是这种递归调用把栈搞坏了?或者说实现上影响了 FFI 调用或者是 luajit?
崩溃的栈因为使用方式不同而不同,这里只贴上面的例子:
#0 0x00007f46bf66cc43 in lj_snap_restore (J=0x7f46c00f9688, exptr=0x7ffed0e347b0) at lj_snap.c:833
#1 0x00007f46bf6874bb in trace_exit_cp (L=<optimized out>, dummy=<optimized out>, ud=0x7ffed0e34750) at lj_trace.c:793
#2 0x00007f46bf64859b in lj_vm_cpcall () from /usr/local/openresty/luajit/lib/libluajit-5.1.so.2
#3 0x00007f46bf688bc6 in lj_trace_exit (J=0x7f46c00f9688, exptr=0x7ffed0e347b0) at lj_trace.c:863
#4 0x00007f46bf64a340 in lj_vm_exit_handler () from /usr/local/openresty/luajit/lib/libluajit-5.1.so.2
#5 0x00000000ffffffff in ?? ()
#6 0x0000000000000000 in ?? ()