我有2个环境(envA,envB)。 envA需要将其请求镜像到envB,并另外两次调用envB,其中包含来自envA中响应的信息。 envA对envB的响应不感兴趣,这本质上是一劳永逸的情况。目的是确保envA的操作和性能绝不会受到对envB的调用的影响。我们选择使用nginx作为代理,并使其进行镜像。我们还编写了一个lua脚本来处理我上面描述的逻辑。
问题在于,即使来自envA服务的响应迅速返回,nginx仍保留envA响应返回给调用方的过程,直到完成对envB的其他3次调用为止。我想以某种方式摆脱这种障碍。
我们的团队没有任何熟悉过lua或nginx的人,所以我敢肯定,我们所拥有的并不是最好/正确的方法...但是到目前为止,我们一直在做调整连接并读取超时,以确保我们将任何阻塞减少到最短的时间。但这只是不能使我们到达想要的位置。
经过研究,我发现https://github.com/openresty/lua-nginx-module#ngxtimerat其中;据我了解与在Java中创建ScheduledThreadPoolExecutor相同,只是将作业排队到其上并将其自身与原始请求流隔离开,从而消除了阻塞。但是我对范围如何变化了解得不够多,以确保我没有搞乱数据/变量明智的方法,而且我也不确定要使用哪个库来调用envB,因为我们一直在使用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;
}
}
}
就我们所看到的问题而言...在通过代理访问envA与不使用envA时,看到的响应时间(秒)增加了。
答案 0 :(得分:1)
发出第一个答案大约五分钟后,我记得有一种正确的方法来进行这种清理活动。
函数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请求,您需要使用cosocket API,该API不支持即开即用的HTTP请求,但是Google快速搜索弹出了this库似乎正是这样做的。
答案 1 :(得分:0)
编辑:很快我就找到了一个更好的解决方案(请参见我的其他答案),但我也将其搁置一旁,因为至少可以从某种意义上知道这样做确实有价值(而且您可能不应该这样做)
我想出的最快的方法就是这个
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()
关闭连接。可以肯定的是,这不是最干净的选择,但是在大多数情况下,它是可行的。如果可以找到更好的解决方案,我会发布另一个答案:)