Я начал использовать Nginx в качестве обратного прокси для набора серверов, которые предоставляют какие-то услуги.
Иногда служба может работать довольно медленно (она работает на Java, а JVM иногда застревает в «полной сборке мусора», что может занять несколько секунд), поэтому я установил proxy_connect_timeout
до 2 секунд, что даст Nginx достаточно времени, чтобы выяснить, что служба застряла на сборке мусора и не отвечает вовремя, и он должен передать запрос другому серверу.
Я также установил proxy_read_timeout
чтобы предотвратить застревание обратного прокси-сервера, если самой службе требуется слишком много времени для вычисления ответа - опять же, он должен переместить запрос на другой сервер, который должен быть достаточно свободным, чтобы вернуть своевременный ответ.
Я провел несколько тестов и ясно вижу, что proxy_connect_timeout
работает правильно, поскольку некоторые запросы возвращаются точно в то время, которое указано для тайм-аута соединения, поскольку служба зависает и не принимает входящие соединения (служба использует Jetty как встроенный контейнер сервлетов). В proxy_read_timeout
также работает, поскольку я вижу запросы, которые возвращаются после указанного там тайм-аута.
Проблема в том, что я ожидал увидеть некоторые запросы с таймаутом после proxy_read_timeout + proxy_connect_timeout
или почти такой промежуток времени, если служба зависает и не принимает соединения, когда Nginx пытается получить к ней доступ, но до того, как Nginx сможет тайм-аут - он освобождается и начинает обработку, но работает слишком медленно, и Nginx прерывается из-за время ожидания чтения. Я считаю, что у службы есть такие случаи, но после выполнения нескольких тестов, в общей сложности несколько миллионов запросов, я не увидел ни одного запроса, который возвращался бы в чем-либо выше proxy_read_timeout
(что является большим таймаутом).
Я был бы признателен за любые комментарии по этой проблеме, хотя я думаю, что это может быть связано с ошибкой в Nginx (я еще не смотрел код, поэтому это всего лишь предположение), что счетчик тайм-аута не сбрасывается после подключения успешно, если Nginx ничего не читал с вышестоящего сервера.
На самом деле мне не удалось воспроизвести это на:
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';
Проблема в том, что я ожидал увидеть некоторые запросы с таймаутом после proxy_read_timeout + proxy_connect_timeout или почти такого промежутка времени, если служба зависла и не будет принимать соединения, когда Nginx пытается получить к ней доступ, но до того, как Nginx сможет тайм-аут - он освобождается и начинает обработку, но работает слишком медленно, и Nginx прекращает работу из-за тайм-аута чтения.
Тайм-аут соединения означает, что TCP останавливается при квитировании (например, не было SYN_ACK). TCP будет повторно пытаться отправить SYN, но вы дали только 2 секунды. к Nginx, чтобы использовать другой сервер, поэтому у него просто нет времени на повторную отправку SYN.
UPD.: Не удалось найти в документации, но tcpdump показывает, что есть 3 сек. задержка между первой отправкой SYN и второй попыткой отправки SYN.