Nginx proxy_read_timeout vs 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), але це може бути неправильним. І все-таки знаючи, що ваша версія допоможе
Мазання

Зверніть увагу, що документи кажуть, що proxy_read_timeoutце не "глобальний час очікування", а між двома операціями читання.
poige

@Sam: Я використовую Nginx 1.0.0. @poige - так, я знаю про це, тому я очікую загальний час очікування proxy_read_timeout + proxy_connect_timeout.
Guss

1
В якості додаткового зауваження, ви, ймовірно, повинні вивчити деякі паралельні настройки сміття для вашого JVM: en.wikipedia.org/wiki/…
поліном

@polynomial: ми це зробили, але, згідно з нашими орієнтирами, функція одночасного збору сміття призводить до того, що загальний час процесора втрачається в загальному обсязі GC порівняно з GC "зупинити світ", тому ми віддаємо перевагу інвестуванню в налаштування 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"

А потім 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';

1
Моє запитання вище, у вашому сценарії, більше схоже на таке: припустимо, тестовий сервер, який приймає з'єднання після випадкового часу між 0 і 20 секундами, а потім чекає випадкового часу між 19 секундами і 21 секундою, перш ніж відповісти. Потім запустіть простий орієнтир проти нього. Я б очікував, що побачимо, що приблизно 50% результатів запитів будуть затримані протягом 10 секунд, 25% - результат із затримкою 20–30 секунд, а 25% отримають успішну відповідь. У такому випадку на скільки успішних запитів знадобиться більше 20 секунд? У моєму орієнтирі жоден з них не є - і це мене непокоїть.
Guss

Я перевірив, встановивши випадкову втрату на SYN, а потім маючи CGI, який витісняв лінії дуже повільно протягом 50 секунд. Мені вдалося побачити запити, що займають набагато довше, ніж обидва тайм-аути разом, але все ще успішні: box.access.log 200: 69.814: 67.100:.: 1579 33 127.0.0.1 test.host - [21 / серпня 2011: 20: 30:52 -0700] "GET / huugs HTTP / 1.1" "-" "-" "-" dev_edge 127.0.0.1:2280 -
поліном

Гаразд, це дивно на зовсім іншому рівні :-). Одне з можливих пояснень полягає в тому, що Nginx вимагає часу, щоб написати запит ( proxy_send_timeout), і, як ви встановили його вище proxy_connection_timeout, це насправді може спричинити будь-яку затримку протягом 20 секунд proxy_read_timeout. Коли ви говорите "виплюньте лінії дуже повільно" - що ви маєте на увазі?
Гасс

сон 1 між друкованими рядками HTML в тілі відповіді. Тільки розкриваємо, як proxy_read_timeout знаходиться між читаннями не всього прочитаного.
многочлен

1
А, бачу. Ну, це точно не моя справа, і мені шкода, що я не прояснив це в моїй ОП. У моєму випадку сервер додатків завершує всю обробку перед поверненням будь-якого виду відповіді, а потім повертає все одразу - тож proxy_read_timeoutабо запит повністю відмовляється, або дозволяє його повністю. Це також пояснює різницю між поведінкою, яку ви бачите, і поведінкою, яку я бачу.
Гасс

3

Проблема полягає в тому, що я б очікував побачити деякі запити, які закінчуються після закінчення proxy_read_timeout + proxy_connect_timeout, або майже за такий проміжок часу, якщо служба застрягла і не прийме з'єднань, коли Nginx намагається отримати доступ до неї, але перш ніж Nginx зможе отримати тайм-аут - він звільняється і починає обробку, але занадто повільний, і Nginx б перервав через час очікування читання.

Тайм-аут підключення означає, що TCP зупиняється при рукостисканні (наприклад, SYN_ACK не було). TCP повторно спробує надіслати SYN, але ви дали лише 2 секунди. до Nginx перейти використовувати інший Сервер, тому у нього просто немає часу на повторне надсилання SYN.

UPD. : Не вдалося знайти в документах, але tcpdump показує, що є 3 сек. затримка між 1-ою відправленою SYN та 2-ю спробою надіслати SYN.


Я не думаю, що це саме те, що я задаю - питання: якщо висхідний потік застрягає і повертає SYN_ACK через 1,999 секунди, чому nginx не продовжить процес із поточним висхідним потоком?
Guss

Що ж, ви можете використовувати sniffer, якщо хочете точно бути впевненим. Може виявитись, що ACK взагалі немає за 2 секунди.
poige

Я не можу реально використовувати sniffer, тому що я сподіваюся, що така поведінка відбудеться там, де є велике навантаження на систему. Пояснення, що ніколи не є ACK пізніше, ніж якийсь X, але раніше, ніж через 2 секунди, навіть якщо враховувати мільйони запитів, здається неправдоподібним.
Guss
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.