我已经开始使用 Nginx 作为提供某种服务的一组服务器的反向代理。
该服务有时会相当慢(它在 Java 上运行,并且 JVM 有时会卡在“完整垃圾收集”中,这可能需要几秒钟),所以我将其设置proxy_connect_timeout
为 2 秒,这将使 Nginx 有足够的时间来确定服务卡在 GC 上并且不会及时响应,并且它应该将请求传递给不同的服务器。
如果服务本身花费太多时间来计算响应,我还设置了proxy_read_timeout
防止反向代理卡住 - 再次,它应该将请求移动到另一台足够空闲的服务器以返回及时的响应。
我运行了一些基准测试,可以清楚地看到,proxy_connect_timeout
由于服务卡住了并且不接受传入连接(服务使用 Jetty 作为嵌入式 servlet 容器),因此某些请求在指定的连接超时时间准确返回,因此可以正常工作。proxy_read_timeout
也可以正常工作,因为我可以看到请求在那里指定的超时后返回。
问题是,proxy_read_timeout + proxy_connect_timeout
如果服务卡住,当 Nginx 尝试访问它时无法接受连接,我本以为会看到一些请求在 或几乎 10 proxy_read_timeout
...
我很感激对这个问题的任何评论,但我认为这可能是由于 Nginx 中的一个错误(我还没有看代码,所以这只是一个假设),如果 Nginx 没有从上游服务器读取任何东西,则在连接成功后超时计数器不会重置。
答案1
我实际上无法重现此问题:
2011/08/20 20:08:43 [notice] 8925#0: nginx/0.8.53
2011/08/20 20:08:43 [notice] 8925#0: built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
2011/08/20 20:08:43 [notice] 8925#0: OS: Linux 2.6.39.1-x86_64-linode19
我在 nginx.conf 中进行了如下设置:
proxy_connect_timeout 10;
proxy_send_timeout 15;
proxy_read_timeout 20;
然后我设置了两个测试服务器。一个只会在 SYN 上超时,另一个会接受连接但从不响应:
upstream dev_edge {
server 127.0.0.1:2280 max_fails=0 fail_timeout=0s; # SYN timeout
server 10.4.1.1:22 max_fails=0 fail_timeout=0s; # accept but never responds
}
然后我发送了一个测试连接:
[m4@ben conf]$ telnet localhost 2480
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: localhost
HTTP/1.1 504 Gateway Time-out
Server: nginx
Date: Sun, 21 Aug 2011 03:12:03 GMT
Content-Type: text/html
Content-Length: 176
Connection: keep-alive
然后查看error_log,其中显示了以下内容:
2011/08/20 20:11:43 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://10.4.1.1:22/", host: "localhost"
然后:
2011/08/20 20:12:03 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:2280/", host: "localhost"
然后是 access.log,预期超时时间为 30 秒(10+20):
504:32.931:10.003, 20.008:.:176 1 127.0.0.1 localrhost - [20/Aug/2011:20:12:03 -0700] "GET / HTTP/1.1" "-" "-" "-" dev_edge 10.4.1.1:22, 127.0.0.1:2280 -
以下是我正在使用的日志格式,其中包括各个上游超时:
log_format edge '$status:$request_time:$upstream_response_time:$pipe:$body_bytes_sent $connection $remote_addr $host $remote_user [$time_local] "$request" "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $edge $upstream_addr $upstream_cache_status';
答案2
问题是,如果服务卡住并且在 Nginx 尝试访问它时不会接受连接,我预计会看到一些请求在 proxy_read_timeout + proxy_connect_timeout 之后超时,或者几乎是那么长的时间,但是在 Nginx 超时之前 - 它被释放并开始处理,但是速度太慢了,Nginx 会因为读取超时而中止。
连接超时意味着 TCP 在握手时停顿(例如,没有 SYN_ACK)。TCP 将重新尝试发送 SYN,但您只给了 Nginx 2 秒钟的时间来使用另一个服务器,因此它根本没有时间重新发送 SYN。
更新。:在文档中找不到,但 tcpdump 显示有3第一次发送 SYN 和第二次尝试发送 SYN 之间的延迟为秒。