Для чего используется параметр keep-alive в HTTP?
Что проверяют
Понимаете ли вы, чего стоит открытие соединения (TCP-рукопожатие, TLS) и зачем его переиспользуют. Следом спрашивают про пул соединений в вашем HTTP-клиенте и про то, что меняется в HTTP/2.
Как отвечать
Keep-alive это постоянное соединение: после ответа TCP-соединение не закрывается, и следующий запрос идёт по нему же. Экономия в том, что не нужно заново делать TCP-рукопожатие и TLS-хендшейк, это один-два RTT на каждый запрос, плюс не сбрасывается разогнанное окно TCP.
- HTTP/1.0: соединение по умолчанию закрывается, постоянное включалось заголовком
Connection: keep-alive; - HTTP/1.1: постоянные соединения по умолчанию, закрыть можно
Connection: close. ЗаголовокKeep-Alive: timeout=5, max=100лишь подсказывает параметры и необязателен; - очередь: в HTTP/1.1 по одному соединению запросы идут последовательно, поэтому клиенты держат пул из нескольких соединений на хост;
- HTTP/2: заголовки
ConnectionиKeep-Aliveзапрещены, одно соединение несёт много параллельных потоков, вопрос решён на уровне протокола.
В Java назовите, где это живёт. java.net.http.HttpClient переиспользует соединения сам, если держать один экземпляр на приложение. В Apache HttpClient 5 это PoolingHttpClientConnectionManager с лимитами на маршрут, в OkHttp ConnectionPool (по умолчанию до 5 простаивающих соединений на 5 минут). На сервере: в Tomcat keepAliveTimeout и maxKeepAliveRequests, в Spring Boot server.tomcat.keep-alive-timeout.
Где спотыкаются
Путают HTTP keep-alive с TCP keepalive (SO_KEEPALIVE). Второе это пробные пакеты ядра, проверяющие, что соединение живо, к переиспользованию для запросов оно отношения не имеет.
Создают новый клиент на каждый запрос. Пул теряется, keep-alive не работает, а под нагрузкой копятся сокеты в TIME_WAIT и кончаются локальные порты.
Не согласуют таймауты. Если балансировщик закрывает простаивающее соединение раньше, чем клиент перестаёт брать его из пула, запросы периодически падают с Connection reset или NoHttpResponseException. Таймаут простоя на клиенте должен быть меньше серверного.