nginx阻塞请求,直到当前请求完成

nginx阻塞请求,直到当前请求完成,nginx,nginx-reverse-proxy,Nginx,Nginx Reverse Proxy,将我的问题归结为最简单的问题:我有一个简单的Flask Web服务器,它有一个GET处理程序,如下所示: @app.route('/', methods=['GET']) def get_handler(): t = os.environ.get("SLOW_APP") app_type = "Fast" if t == "1": app_type = "Slow"

将我的问题归结为最简单的问题:我有一个简单的Flask Web服务器,它有一个GET处理程序,如下所示:

@app.route('/', methods=['GET'])
def get_handler():
    t = os.environ.get("SLOW_APP")
    app_type = "Fast"
    if t == "1":
       app_type = "Slow"
       time.sleep(20)
    return "Hello from Flask, app type = %s" % app_type 
upstream myproject {
  server host.docker.internal:8000;
  server host.docker.internal:8001;
}

server {
  listen 8888;
  #server_name www.domain.com;
  location / {
    proxy_pass http://myproject;
  }
}
我在两个不同的端口上运行此应用程序:一个端口8000上没有设置SLOW_app环境变量,另一个端口8001上设置了SLOW_app环境变量。 接下来,我有一个nginx反向代理,它的上游有这两个appserver实例。我使用docker运行所有程序,因此我的nginx conf如下所示:

@app.route('/', methods=['GET'])
def get_handler():
    t = os.environ.get("SLOW_APP")
    app_type = "Fast"
    if t == "1":
       app_type = "Slow"
       time.sleep(20)
    return "Hello from Flask, app type = %s" % app_type 
upstream myproject {
  server host.docker.internal:8000;
  server host.docker.internal:8001;
}

server {
  listen 8888;
  #server_name www.domain.com;
  location / {
    proxy_pass http://myproject;
  }
}
它可以工作,但如果我打开两个浏览器窗口并键入localhost,它会首先命中速度较慢的服务器,需要20秒,在此期间,第二个浏览器似乎会阻止等待第一个请求完成。最后,我看到第一个请求由“slow”服务器提供服务,第二个请求由“fast”服务器提供服务(no time.sleep())。为什么nginx似乎会阻止第二个请求直到第一个请求完成


否,如果第一个请求转到速度较慢的服务器(需要20秒),并且在该延迟期间,如果我再次从浏览器发出请求,它将转到第二个服务器,但只有在第一个服务器完成后

我与我们的工程团队在这方面进行了合作,可以分享以下见解:

我们的实验室环境

卢阿 这与我们代理流量的另一个第三方应用程序的设置相同。但我已经用您的问题中共享的一个NGINX配置和两个基于NodeJS的上游应用程序测试了相同的功能

NodeJS 正常的

const express = require('express');
const app = express();
const port = 3001;

app.get ('/', (req,res) => {
  res.send('Hello World')

});

app.listen(port, () => {
  console.log(`Example app listening on ${port}`)
})

测试 由于我们使用的是NGINX-OSS,因此负载平衡协议将是RoundRobin(RR)。我们使用
ap
从另一台服务器进行的第一次测试。结果是:

Concurrency Level:      10
Time taken for tests:   25.056 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      17400 bytes
HTML transferred:       1700 bytes
Requests per second:    3.99 [#/sec] (mean)
Time per request:       2505.585 [ms] (mean)
Time per request:       250.559 [ms] (mean, across all concurrent requests)
Transfer rate:          0.68 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       5
Processing:     0 2505 2514.3   5001    5012
Waiting:        0 2504 2514.3   5001    5012
Total:          1 2505 2514.3   5001    5012
Percentage of the requests served within a certain time (ms)
  50%   5001
  66%   5005
  75%   5007
  80%   5007
  90%   5010
  95%   5011
  98%   5012
  99%   5012
 100%   5012 (longest request)
50%的请求速度较慢。这完全没关系,因为我们有一个“慢”的例子。使用
curl
进行相同的测试。同样的结果。根据NGINX服务器的调试日志,我们看到请求在传入时被处理,并被发送到慢速或快速后端(基于roundrobin)

因此,这意味着“nginx阻塞请求直到当前请求完成”的行为在实例上是不可复制的。但我可以在Chrome浏览器中重现你的问题。点击慢实例会让另一个浏览器窗口等待第一个得到响应。在客户端进行了一些内存分析和调试之后,我遇到了浏览器的连接池

浏览器使用与服务器相同的、已建立的连接。如果此连接被等待的请求(相同的数据、相同的cookie…)占用,它将不会从池中打开新连接。它将等待第一个请求完成。您可以通过向请求添加缓存buster或新的头、新cookie来解决此问题。比如:

http://10.172.1.120:8080/?ofdfu9aisdhffadf
。在另一个浏览器窗口等待响应时,在新的浏览器窗口中发送此消息。这将显示一个即时响应(假设没有其他对后端的请求,因为基于RR->如果有对慢的请求,下一个将是快的)


如果您从不同的客户端发送请求,同样适用。这也会起作用。

您好-我目前正在调查此事。我可以复制,但不能完全复制。看起来,当我到达慢速上行时,下一个请求将再次发送到慢速服务器。我们有几个选项可以调整负载平衡,但大多数选项只适用于NGINX Plus.DR;TL浏览器执行连接池。长答案将在一点后提供。不,如果第一个请求转到速度较慢的服务器(需要20秒),并且在延迟期间,如果我再次从浏览器发出请求,它将转到第二个服务器,但只有在第一个请求完成后。我看到第一个浏览器显示“慢应用”,第二个请求显示“快应用”,感谢您的研究和详细解释。你是说如果我使用chrome浏览器和safari,我不会看到这个问题吗?如果我同时使用safari和chrome,请求将独立处理,没有其他额外的延迟。听到这个消息很好!!!欢迎你!我很好奇你的问题的根本原因是什么。
2021/04/08 15:26:18 [debug] 8995#8995: *1 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *1 get rr peer, current: 000055B815BD4388 -100
2021/04/08 15:26:18 [debug] 8995#8995: *4 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *4 get rr peer, current: 000055B815BD4540 0
2021/04/08 15:26:18 [debug] 8995#8995: *5 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *5 get rr peer, current: 000055B815BD4388 -100
2021/04/08 15:26:18 [debug] 8995#8995: *7 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *7 get rr peer, current: 000055B815BD4540 0
2021/04/08 15:26:18 [debug] 8995#8995: *10 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *10 get rr peer, current: 000055B815BD4388 -100
2021/04/08 15:26:18 [debug] 8995#8995: *13 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *13 get rr peer, current: 000055B815BD4540 0
2021/04/08 15:26:18 [debug] 8995#8995: *16 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *16 get rr peer, current: 000055B815BD4388 -100
2021/04/08 15:26:18 [debug] 8995#8995: *19 get rr peer, try: 2
2021/04/08 15:26:18 [debug] 8995#8995: *19 get rr peer, current: 000055B815BD4540 0