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.