Keepalive до апстрима в nginx: где теряются соединения

30 сентября 2026 · 6 минут

По умолчанию nginx общается с апстримом по HTTP/1.0 и закрывает соединение после каждого ответа. При высокой нагрузке это тысячи сокетов в TIME_WAIT и лишние миллисекунды на установку TCP, а для HTTPS-апстрима ещё и полный TLS-хендшейк.

Минимальная настройка

upstream app {
    server 10.0.0.5:8080;
    keepalive 32;
}

server {
    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Важны все три строки. Без proxy_http_version 1.1 keepalive не работает, а без очистки заголовка Connection клиентский close уедет к апстриму.

Как проверить

ss -tan state time-wait '( dport = :8080 )' | wc -l

До изменения счётчик растёт вместе с RPS, после — держится около нуля, а число установленных соединений примерно равно значению keepalive, умноженному на число воркеров.

Подводные камни

  • keepalive — это размер пула простаивающих соединений на воркер, а не лимит.
  • Апстрим может закрывать соединения раньше nginx. Держите keepalive_timeout в upstream меньше, чем таймаут приложения.
  • Для WebSocket нужен отдельный location с заголовками Upgrade.