Прямой ответ
Механизм keepalive отправляет проверочные сегменты по неактивному соединению, поэтому разрыв обнаруживается без обмена данными. Без проверок соединение остаётся открытым неограниченно долго.
| Параметр | Назначение |
|---|---|
| Время до первой проверки | Период неактивности перед началом проверок |
| Интервал проверок | Период между проверочными сегментами |
| Число попыток | Количество проверок без ответа до закрытия |
import socket
s = socket.create_connection(("host", 5432))
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)
Параметры задаются на уровне сокета, поэтому значение по умолчанию системы переопределяется для конкретного соединения. О жизненном цикле соединения — в статье про TCP-рукопожатие.
Время обнаружения и отличие от прикладного контроля
Время обнаружения разрыва определяется произведением параметров, поэтому настройка влияет на скорость реакции.
Расчёт времени. Общее время составляет период неактивности плюс произведение интервала проверок на число попыток. Сокращение параметров ускоряет обнаружение, но увеличивает объём проверочного трафика.
Прикладной контроль. Приложение отправляет собственный проверочный запрос и ожидает ответ, поэтому контролирует не только соединение, но и работоспособность сервиса. Механизм уровня транспорта подтверждает только доступность пути.
Практическое следствие: keepalive обнаруживает разрыв соединения, но не подтверждает работоспособность приложения на другом конце.
Отдельный аспект — промежуточное оборудование. Прокси либо балансировщик может закрывать неактивное соединение раньше, чем срабатывает keepalive, поэтому период неактивности выбирается меньше таймаута промежуточного узла.
Три признака некорректной настройки.
Период неактивности больше таймаута промежуточного узла. Соединение закрывается промежуточным оборудованием до первой проверки.
Избыточно частые проверки. Объём проверочного трафика растёт, поэтому нагрузка увеличивается без необходимости.
Отсутствие keepalive в пуле соединений. Соединение в пуле остаётся открытым после разрыва, поэтому первый запрос завершается ошибкой.
О пулах соединений — в статье про пулы соединений; о таймаутах операций — в статье про сетевые таймауты.
Keepalive в пуле соединений и проверка перед выдачей
Соединение в пуле удерживается длительное время, поэтому контроль доступности выполняется на двух уровнях.
Периодическая проверка. Механизм уровня транспорта отправляет проверочные сегменты по неактивному соединению, поэтому разрыв обнаруживается до попытки передачи данных.
Проверка перед выдачей. Соединение проверяется в момент выдачи из пула, поэтому разорванное соединение не передаётся приложению. Проверка выполняется быстрым запросом, поэтому задержка выдачи мала.
Исключение соединения из пула. Соединение, не прошедшее проверку, закрывается и исключается из пула, поэтому повторная выдача не выполняется.
Практическое следствие: сочетание периодической проверки и проверки перед выдачей обеспечивает, что приложение получает работоспособное соединение, а разрыв обнаруживается без участия приложения.
Отдельный аспект — стоимость проверки. Проверка перед выдачей добавляет время к получению соединения, поэтому применяется быстрый запрос либо проверка состояния сокета без обмена данными.
Проверка фактического срабатывания keepalive
Настроенные параметры подтверждаются наблюдением за обменом проверочных сегментов.
Захват проверочных сегментов. Захват на интерфейсе показывает отправку проверочных сегментов по неактивному соединению, поэтому факт работы механизма подтверждается.
Наблюдение закрытия соединения. Соединение закрывается после исчерпания числа попыток, поэтому фактическое время обнаружения разрыва измеряется.
Практическое следствие: расчётное время обнаружения подтверждается наблюдением, поскольку параметры могут переопределяться на уровне системы.
Практика: настройка обнаружения разрыва
1. Включите keepalive для длительных соединений. Соединение, удерживаемое длительное время, требует контроля доступности.
2. Задайте параметры на уровне сокета. Значение по умолчанию системы может не соответствовать требованию приложения.
3. Выберите период неактивности меньше таймаута промежуточного узла. Соединение не должно закрываться промежуточным оборудованием до проверки.
4. Ограничьте число попыток. Избыточное число увеличивает время обнаружения разрыва.
5. Используйте прикладной контроль для проверки сервиса. Ответ на проверочный запрос подтверждает работоспособность приложения.
6. Проверяйте поведение пула соединений. Соединение в пуле проверяется перед выдачей, поэтому разорванное соединение не передаётся приложению.
7. Измеряйте фактическое время обнаружения. Расчётное время подтверждается наблюдением за закрытием соединения.
Рекомендации:
- Различайте контроль соединения и контроль сервиса. Keepalive подтверждает доступность пути, прикладной запрос — работоспособность приложения.
- Учитывайте объём проверочного трафика. Частые проверки увеличивают нагрузку, поэтому интервал выбирается по требованию к скорости обнаружения.
- Проверяйте таймауты промежуточного оборудования. Прокси либо балансировщик закрывает неактивное соединение по собственному таймауту.
- Фиксируйте параметры в конфигурации. Значения по умолчанию системы различаются, поэтому параметры задаются явно.
- Пересматривайте при изменении топологии. Добавление промежуточного узла изменяет таймаут неактивности.
Практический сценарий: первый запрос после простоя завершался ошибкой
Контекст: соединение из пула выдавалось приложению, при этом первый запрос завершался ошибкой соединения.
- Диагностика. Соединение в пуле удерживалось длительное время без обмена данными. Промежуточный узел закрыл соединение по таймауту неактивности, при этом приложение не получило уведомления, поэтому соединение считалось открытым.
- Причина. Keepalive не был включён, поэтому разрыв не обнаруживался до попытки передачи данных. Период неактивности превышал таймаут промежуточного узла.
- Действия. (а) Включили keepalive для соединений пула с периодом неактивности меньше таймаута промежуточного узла; (б) добавили проверку соединения перед выдачей из пула; (в) сократили интервал проверок и число попыток, чтобы разрыв обнаруживался быстрее; (г) измерили фактическое время обнаружения разрыва; (д) добавили повтор запроса при ошибке соединения, поскольку первый запрос после разрыва завершается ошибкой.
- Результат. Разорванные соединения не выдаются приложению, поскольку разрыв обнаруживается до передачи данных.
Вывод: соединение, удерживаемое без обмена данными, может быть закрыто промежуточным узлом без уведомления приложения. Keepalive с периодом неактивности меньше таймаута промежуточного узла обнаруживает разрыв до передачи данных.
FAQ
Что обнаруживает keepalive? Разрыв соединения на уровне транспорта. Работоспособность приложения на другом конце не подтверждается, поэтому требуется прикладной проверочный запрос.
Как рассчитывается время обнаружения разрыва? Период неактивности плюс произведение интервала проверок на число попыток. Сокращение параметров ускоряет обнаружение.
Нужен ли keepalive в пуле соединений? Да, соединение в пуле удерживается длительное время, поэтому разрыв должен обнаруживаться до выдачи соединения приложению.
Может ли промежуточное оборудование закрыть соединение раньше? Да, прокси либо балансировщик закрывает неактивное соединение по собственному таймауту. Период неактивности выбирается меньше этого таймаута.
Источники: tcp man page, Python socket, RFC 9293 — ссылки в шапке.