lua 合并接口请求

yuyu888 于 2020-12-22 发布

配置依赖

location /api1 {
    echo_sleep 3;
    echo api1 : $arg_a;
}
location /api2 {
    echo_sleep 3;
    echo api2 : $arg_a;
}

串行实现

location /serial {
    content_by_lua '
        local t1 = ngx.now()
        local res1 = ngx.location.capture("/api1", {args = ngx.req.get_uri_args()})
        local res2 = ngx.location.capture("/api2", {args = ngx.req.get_uri_args()})
        local t2 = ngx.now()
        ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
    ';
}

并行实现

location /concurrency1 {
    content_by_lua '
        local t1 = ngx.now()
        local res1,res2 = ngx.location.capture_multi({
              {"/api1", {args = ngx.req.get_uri_args()}},
              {"/api2", {args = ngx.req.get_uri_args()}}
        })
        local t2 = ngx.now()
        ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
    ';
}

协程实现

Lua中没有线程和异步编程编程的概念,对于并发执行提供了协程的概念,个人认为协程是在A运行中发现自己忙则把CPU使用权让出来给B使用,最后A能从中断位置继续执行,本地还是单线程,CPU独占的;因此如果写网络程序需要配合非阻塞I/O来实现。 ngx_lua 模块对协程做了封装,我们可以直接调用ngx.thread API使用,虽然称其为“轻量级线程”,但其本质还是Lua协程。该API必须配合该ngx_lua模块提供的非阻塞I/O API一起使用,比如我们之前使用的ngx.location.capture_multi和lua-resty-redis、lua-resty-mysql等基于cosocket实现的都是支持的。 通过Lua协程我们可以并发的调用多个接口,然后谁先执行成功谁先返回,类似于BigPipe模型。

location /concurrency2 {
    content_by_lua '
        local t1 = ngx.now()
        local function capture(uri, args)
           return ngx.location.capture(uri, args)
        end
        local thread1 = ngx.thread.spawn(capture, "/api1", {args = ngx.req.get_uri_args()})
        local thread2 = ngx.thread.spawn(capture, "/api2", {args = ngx.req.get_uri_args()})
        local ok1, res1 = ngx.thread.wait(thread1)
        local ok2, res2 = ngx.thread.wait(thread2)
        local t2 = ngx.now()
        ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
    ';
}

任意成功即返回

local  ok, res = ngx.thread.wait(thread1, thread2)