我有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()
关闭连接。可以肯定的是,这不是最干净的选项,但在大多数情况下它可以使用。如果我能找到一个更好的解决方案,我会发出另一个答案:(