Я потратил довольно много времени на то, чтобы отследить проблему на производстве, когда исчезновение сервера базы данных может привести к зависанию до 2 часов (долгое ожидание poll()
вызова в клиентской библиотеке libpq) для подключенного клиента. Углубившись в проблему, я понял, что эти параметры ядра должны быть скорректированы до минимума, чтобы разорванные TCP-соединения были замечены своевременно:
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries2 = 15
Четыре значения выше взяты из машины с Ubuntu 12.04, и похоже, что эти значения по умолчанию не отличаются от текущих значений по умолчанию для ядра Linux .
Эти настройки, кажется, сильно смещены в сторону сохранения существующего соединения открытыми и чрезвычайно скупы на пробные сообщения проверки активности. AIUI, значение tcp_keepalive_time
по умолчанию, равное 2 часам, означает, что, когда мы ожидаем ответа для удаленного хоста, мы будем терпеливо ждать в течение 2 часов, прежде чем запустить проверку активности, чтобы убедиться, что наше соединение все еще действует. И затем, если удаленный хост не отвечает на тест активности активности, мы повторяем эти тесты активности 9 раз ( tcp_keepalive_probes
) с интервалом 75 секунд ( tcp_keepalive_intvl
), так что это дополнительные 11 минут, прежде чем мы решим, что соединение действительно разорвано.
Это соответствует тому, что я видел в поле: например, если я запускаю psql
сеанс, подключенный к удаленному экземпляру PostgreSQL, с некоторым запросом, ожидающим ответа, например
SELECT pg_sleep(30);
и затем, когда удаленный сервер умирает ужасной смертью (например, отбрасывает трафик на эту машину), я вижу, что мой psql-сеанс ждет до 2 часов и 11 минут, прежде чем он обнаружит, что его соединение разорвано. Как вы можете себе представить, эти настройки по умолчанию вызывают серьезные проблемы для кода, с которым мы общаемся в базе данных, например, при сбое базы данных. Отключение этих ручек очень помогло! И я вижу, что я не одинок в том, что рекомендую скорректировать эти значения по умолчанию.
Итак, мои вопросы:
- Как долго значения по умолчанию были такими?
- Каково было исходное обоснование для того, чтобы сделать эти настройки TCP настройками по умолчанию?
- Какие-нибудь дистрибутивы Linux меняют эти значения по умолчанию?
И любая другая история или взгляд на обоснование этих настроек будут оценены.
TCP_KEEPIDLE
, TCP_KEEPCNT
и TCP_KEEPINTVL
.
TCP_USER_TIMEOUT
, вместо настройки net.ipv4.tcp_retries2
всей системы. Конечно, многие приложения (такие как PostgreSQL в моем примере здесь) еще не поддерживают TCP_USER_TIMEOUT
.