问题隔离原始请求和nginx中的镜像请求



我有2个环境(Enva,Envb(。Enva需要将其请求反映给ENVB,并向Envb拨打Envb的其他两个电话,其中包含Enva中的响应中的信息。Enva对EnvB的反应不感兴趣,这本质上是火灾和忘记情况。目的是确保Enva的操作和性能绝不会受到对Envb的电话的影响。我们选择使用nginx作为代理,并进行镜像。我们还编写了一个LUA脚本来处理我上面描述的逻辑。

问题在于,即使Enva服务的响应很快就会恢复,NGINX仍将Enva响应返回对呼叫者的返回,直到使用其他3个对Envb的电话完成。我想以某种方式摆脱这种障碍。

我们的团队没有任何经验丰富的LUA或NGINX的人,所以我敢肯定,我们拥有的不是最好/正确的方法...但是到目前为止,我们一直在做什么是为了调整连接并阅读超时,以确保我们将任何阻塞都减少到最短时间。但这只是没有让我们进入我们想要的地方。

进行了一些研究后,我找到了https://github.com/openresty/lua-nginx-module#ngxtimerat;正如我所理解的;将与在Java中创建一个计划的threadpoolexecutor相同,而只是将作业纳入其中,并与原始请求的流程隔离,从而消除了阻塞。但是,我对范围如何变化不太了解,无法确保我不会搞砸数据/可变的明智之举,而且我也不确定要使用哪些库来拨打ngx,所以我不确定要使用什么库.location.capture到目前为止,根据上面链接中的文档,使用ngx.timer.at时,这不是一个选项。因此,我希望对如何正确使用ngx.timer.at或其他方法来实现这一目标的任何见解。

这是我们正在使用的LUA代码。我把它弄得很大但是我们拥有的骨头,主要部分是content_by_lua_block部分

http {
    upstream envA {
        server {{getenv "ENVA_URL"}};
    }
    upstream envB {
        server {{getenv "ENVB_URL"}};
    }
    server {
        underscores_in_headers on;
        aio threads=one;
        listen       443 ssl;
        ssl_certificate     {{getenv "CERT"}};
        ssl_certificate_key {{getenv "KEY"}};
        location /{{getenv "ENDPOINT"}}/ {
            content_by_lua_block {
                ngx.req.set_header("x-original-uri", ngx.var.uri)
                ngx.req.set_header("x-request-method", ngx.var.echo_request_method)
                resp = ""
                ngx.req.read_body()
                if (ngx.var.echo_request_method == 'POST') then
                    local request = ngx.req.get_body_data()
                    resp = ngx.location.capture("/envA" .. ngx.var.request_uri, { method = ngx.HTTP_POST })
                    ngx.location.capture("/mirror/envB" .. ngx.var.uri, { method = ngx.HTTP_POST })
                    ngx.location.capture("/mirror/envB/req2" .. "/envB/req2", { method = ngx.HTTP_POST })
                    ngx.status = resp.status
                    ngx.header["Content-Type"] = 'application/json'
                    ngx.header["x-original-method"] = ngx.var.echo_request_method
                    ngx.header["x-original-uri"] = ngx.var.uri
                    ngx.print(resp.body)
                    ngx.location.capture("/mirror/envB/req3" .. "/envB/req3", { method = ngx.HTTP_POST, body = resp.body })
                 end
            }
         }
        location /envA {
            rewrite /envA(.*) $1  break;
            proxy_pass https://envAUrl;
            proxy_ssl_certificate     {{getenv "CERT"}};
            proxy_ssl_certificate_key {{getenv "KEY"}};
        }
        ###############################
        # ENV B URLS
        ###############################
        location /envB/req1 {
            rewrite /envB/req1(.*) $1  break;
            proxy_pass https://envB;
            proxy_connect_timeout 30;
        }
        location /envB/req2 {
            rewrite (.*) /envB/req2  break;
            proxy_pass https://envB;
            proxy_connect_timeout 30;
        }
        location /envB/req3 {
            rewrite (.*) /envB/req3 break;
            proxy_pass https://envB;
            proxy_connect_timeout 30;
        }
     }
}

就我们看到的问题而言...当我们不使用它时,当它通过此代理时,我们会看到响应时间增加(秒(。

发送第一个答案几乎五分钟,我记得有一种正确的清理活动方法。

函数ngx.timer.at允许您安排在一定时间之后运行的功能,包括当前处理程序完成后立即使用的0。您可以使用它来安排您的清理职责和其他措施,以返回客户,并以干净的方式结束请求。

这是一个示例:

content_by_lua_block {
    ngx.say 'Hello World!'
    ngx.timer.at(0, function(_, time)
        local start = os.time()
        while os.difftime(os.time(), start) < time do
        end
        os.execute('DISPLAY=:0 zenity --info --width 300 --height 100 --title "Openresty" --text "Done processing stuff :)"')
    end, 3)
}

请注意,我使用zenity显示带有消息的弹出窗口,因为我没有设置任何东西来检查它是否真正被调用。


编辑:我可能应该提到要在计划的事件中发送HTTP请求,您需要使用COSOCKECT API,该API不支持HTTP请求,但是快速的Google搜索将带来这个库似乎就是这样做。

编辑:我不花很长时间找到一个更好的解决方案(请参阅我的其他答案(,但是我也把它留下来,因为至少可能有一些知道这确实有效的价值(并且您可能不应该这样做(

我想出的最快的事情是这个

        content_by_lua_block {
            ngx.say 'Hello World!'
            local start = os.time()
            ngx.flush()
            ngx.req.socket:close()
            while os.difftime(os.time(), start) < 4 do
            end
        }

首先使用ngx.flush()将实际输出汇总到客户端,然后使用ngx.req.socket:close()关闭连接。可以肯定的是,这不是最干净的选项,但在大多数情况下它可以使用。如果我能找到一个更好的解决方案,我会发出另一个答案:(

最新更新