# конспект · шаг 5 из 5
Конспект: WebSocket, таймауты, буферизация
WebSocket, таймауты и буферизация - три темы, где «работает на тесте, падает на проде».
WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location /ws/ {
proxy_pass http://app:8000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
map нужен, чтобы обычные запросы не получали Connection: upgrade.
Свежее: proxy_http_version 1.1; из старых руководств больше не нужен - с
nginx 1.29.7 значение по умолчанию и так 1.1, Connection: close бэкенду не
шлётся, а keepalive в upstream включён сам.
Таймауты
| Директива | Что ограничивает | Умолчание |
|---|---|---|
proxy_connect_timeout |
установку соединения с бэкендом | 60s (больше 75s нельзя) |
proxy_send_timeout |
передачу запроса бэкенду | 60s |
proxy_read_timeout |
ожидание между частями ответа | 60s |
proxy_read_timeout - это пауза между чтениями, а не общее время ответа. Отсюда
504 у долгих отчётов: бэкенд молчит 90 секунд, потом отдаёт всё сразу - но nginx
уже ушёл.
Буферизация
По умолчанию nginx буферизует ответ: забирает у бэкенда быстро, отдаёт клиенту медленно и тем освобождает бэкенд. Замер на 50 МБ и клиенте 50 КБ/с:
| настройка | бэкенд |
|---|---|
proxy_buffering on |
отдал за 0,26 с и свободен |
proxy_buffering off |
держал соединение, пока клиент не ушёл |
on + proxy_max_temp_file_size 0 |
держал, как при off |
Выигрыш даёт временный файл: буферов всего восемь по 16 КБ.
Поток она задерживает не всегда. Время до первого байта на ответе из четырёх кусков по секунде:
| как устроен ответ | on |
off |
|---|---|---|
Transfer-Encoding: chunked |
0,0015 с | 0,0014 с |
объявлен Content-Length |
4,005 с | 0,0015 с |
chunked плюс gzip |
4,003 с | 0,0015 с |
Чанкованный поток проходит и с буферизацией. Копится ответ с объявленной длиной
и ответ под сжатием. Потоковый маршрут лечат точечным proxy_buffering off с
gzip off; либо заголовком X-Accel-Buffering: no от самого приложения.
Ловушки джокера
- 502
upstream sent too big header- раздутые cookie сессии не влезли вproxy_buffer_size. Лечится увеличением, а не перезапуском бэкенда. - WebSocket «рвётся раз в минуту» -
proxy_read_timeoutпо умолчанию 60 секунд, замер даёт 60,1. Любой кадр в канале сбрасывает отсчёт, поэтому таймаут поднимают и добавляют ping. - Одного
Connectionмало - безUpgradeбэкенд отвечает 200 вместо 101. - Любой свой
proxy_set_headerв блоке уносит заголовки апгрейда, включая безобидную строку сHost. proxy_buffering offглобально «чтобы шло сразу» - ошибка: чанкованный ответ идёт сразу и без этого, а воркер бэкенда окажется занят на всё время скачивания у всех маршрутов.- Keepalive к бэкенду работает только через
upstream. Замер: шесть запросов к литеральному адресу - шесть соединений, к той же машине внутри группы - одно. - С 1.31.0 nginx отклоняет h2/h3-запросы с хоп-хоп-заголовками, поэтому WebSocket живёт отдельным HTTP/1.1-соединением - это норма, а не поломка.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий