Nginx proxy_read_timeout 대 proxy_connect_timeout


15

Nginx를 일종의 서비스를 제공하는 서버 세트의 리버스 프록시로 사용하기 시작했습니다.

서비스는 때때로 느려질 수 있습니다 (Java에서 실행되고 JVM은 때때로 "전체 가비지 수집"에 몇 초가 걸릴 수 있음). 따라서 proxy_connect_timeout2 초로 설정하면 Nginx가 알아낼 시간이 충분합니다. 서비스가 GC에 멈춰 있고 시간 내에 응답하지 않으며 요청을 다른 서버로 전달해야합니다.

또한 proxy_read_timeout서비스 자체가 응답을 계산하는 데 너무 많은 시간이 걸리면 리버스 프록시가 멈추지 않도록 설정 했습니다. 다시 요청을 적시에 응답을 반환 할 수있는 다른 서버로 이동해야합니다.

일부 벤치 마크를 실행 proxy_connect_timeout했으며 서비스가 멈추고 들어오는 연결을 수락하지 않기 때문에 일부 요청이 연결 시간 초과에 지정된 시간에 정확하게 반환되므로 제대로 작동 한다는 것을 분명히 알 수 있습니다 (서비스는 Jetty를 내장 된 것으로 사용합니다) 서블릿 컨테이너). 는 proxy_read_timeout내가 타임 아웃 후 반환이를 지정한 요청을 볼 수도 작동합니다.

문제는 proxy_read_timeout + proxy_connect_timeout서비스가 멈추고 Nginx가 액세스하려고 시도 할 때 연결을 수락하지 않으면 Nginx가 시간 초과하기 전에 요청이 시간 초과 또는 거의 그 시간이 걸리는 것으로 예상 한다는 것입니다. 처리를 시작하지만 너무 느리고 읽기 시간 초과로 인해 Nginx가 중단됩니다. 서비스에 그러한 사례가 있다고 생각하지만 몇 가지 벤치 마크를 실행하여 총 수백만 건의 요청을 처리 한 결과 위의 항목 proxy_read_timeout(더 큰 시간 초과)으로 반환되는 단일 요청을 보지 못했습니다 .

이 문제에 대한 의견을 보내 주시면 Nginx의 버그 때문일 수 있습니다 (아직 코드를 보지 않았으므로 가정 사항입니다). 연결 후 시간 초과 카운터가 재설정되지 않습니다. Nginx가 업스트림 서버에서 아무것도 읽지 않으면 성공합니다.


1
어떤 버전의 NGINX? 나는 이전 버전 (약 0.6 / 7)과 비슷한 것을 기억하지만 더 최신 버전 (최신 안정 버전 1.0.5)으로 수정되었지만 잘못되었을 수 있습니다. 아직도 당신의 버전을 아는 것이 도움이 될 것입니다
Smudge

문서 proxy_read_timeout가 "글로벌 타임 아웃"이 아니라 2 번의 읽기 작업 사이 라고 말합니다 .
poige

@ Sam : Nginx 1.0.0을 사용하고 있습니다. @poige-예, 알고 있습니다 proxy_read_timeout + proxy_connect_timeout. 그래서 총 시간 초과가 예상 됩니다.
거스

1
보조 노트로서, 당신은 아마 당신의 JVM에 대한 몇 가지 동시 가비지 컬렉션 튜닝을 연구해야합니다 en.wikipedia.org/wiki/...
다항식

@polynomial : 벤치 마크에 따르면 동시 가비지 콜렉션 기능을 통해 "세계를 중지"하는 GC에 비해 GC에 더 많은 CPU 시간이 손실되므로 Nginx 튜닝에 투자하는 것이 좋습니다 :-)
Guss

답변:


18

실제로 이것을 재현 할 수 없었습니다.

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"

그런 다음 30 초의 타임 아웃 (10 + 20)이있는 access.log :

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';

1
귀하의 시나리오에서 위의 질문은 다음과 같습니다. 테스트 서버가 0에서 20 초 사이의 임의의 시간 후에 연결을 수락하고 응답하기 전에 19 초에서 21 초 사이의 임의의 시간을 기다린다고 가정하십시오. 그런 다음 간단한 벤치 마크를 실행하십시오. 10 초 시간 초과로 요청 결과의 약 50 %, 20 ~ 30 초 시간 초과로 25 % 결과 및 25 %가 성공적인 응답을받을 것으로 예상됩니다. 이 경우 완료에 20 초 이상 걸리는 성공적인 요청 수는 몇 개입니까? 내 벤치 마크에서는 그중 어느 것도 없습니다.
Guss

SYN에서 임의의 손실을 설정 한 다음 약 50 초 동안 선을 천천히 뱉어내는 CGI를 테스트했습니다. box.access.log 200 : 69.814 : 67.100 :. : 1579 33 127.0.0.1 test.host-[21 / Aug / 2011 : 20 : 두 타임 아웃이 결합 된 것보다 훨씬 오래 걸리는 요청을 볼 수있었습니다. 30:52 -0700] "GET / huugs HTTP / 1.1" "-" "-" "-"127.0.0.1:2280를 dev_edge -
다항식

좋아, 그것은 완전히 다른 수준에서 이상합니다 :-). 한 가지 가능한 설명은 Nginx가 요청을 작성하는 데 시간이 걸리고 요청 proxy_send_timeout을 더 높게 설정하면 proxy_connection_timeout실제로 20 초 동안 지연 될 수 있다는 것 proxy_read_timeout입니다. "정말 천천히 선을 내뱉다"고 말할 때-무슨 뜻입니까?
Guss

응답 본문에서 HTML 인쇄 행 사이의 수면 1 proxy_read_timeout이 전체 읽기가 아닌 읽기 사이에 어떻게 노출되는지를 노출시키는 것입니다.
다항식

1
아, 알겠습니다 글쎄, 이것은 확실히 내 경우가 아니며 OP에 명확하게 표시하지 않아서 죄송합니다. 필자의 경우 응용 프로그램 서버는 모든 종류의 응답을 반환하기 전에 전체 처리를 완료 한 다음 모든 것을 한 번에 반환하므로 proxy_read_timeout요청이 완전히 실패하거나 완전히 허용됩니다. 이것은 또한 당신이 보는 행동과 내가 보는 행동의 차이점을 설명합니다.
거스

3

문제는 proxy_read_timeout + proxy_connect_timeout 이후에 시간 초과되거나 Nginx가 액세스하려고 시도 할 때 서비스가 중단되어 연결을 수락하지 않으면 Nginx가 시간 초과되기 전에 시간이 초과되는 요청을 볼 수 있다는 것입니다. 해제되어 처리를 시작하지만 너무 느리고 읽기 시간 초과로 인해 Nginx가 중단됩니다.

연결 시간 초과는 핸드 셰이 킹시 (예 : SYN_ACK가 없음) TCP 정지를 의미합니다. TCP는 SYN 전송을 재 시도하지만 2 초만 제공했습니다. 다른 서버를 사용하기 위해 Nginx로 이동하므로 SYN을 다시 보낼 시간이 없습니다.

UPD. : 문서에서 찾을 수 없지만 tcpdump에 3 초가 있음이 표시 됩니다. 첫 번째 SYN 전송과 두 번째 SYN 전송 시도 사이의 지연.


나는 이것이 내가 묻는 것과 정확히 같지 않다-질문은 : 업스트림이 멈추고 1.999 초 후에 SYN_ACK를 반환하면 왜 nginx가 현재 업스트림으로 프로세스를 계속하지 않습니까?
거스

정확히 알고 싶다면 스니퍼를 사용할 수 있습니다. <2 초 내에 ACK가 전혀 없음이 밝혀 질 수 있습니다.
poige

시스템에 부하가 많은 곳에서이 동작이 발생하기를 기대하기 때문에 스니퍼를 실제로 사용할 수 없습니다. 수백만 건의 요청을 고려할 때조차도 X 이후에는 ACK가 없으며 2 초 이전에는 ACK가 없다는 설명은 그럴듯 해 보이지 않습니다.
Guss
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.