한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

Анатомия игровых лагов › L7 ОС сервера (ядро)

Исчерпание эфемерных портов в межсерверных соединениях Ephemeral port exhaustion (TIME_WAIT)

ID причины so-ports · Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Серверная инфраструктура

Открыть карточку в основной версии с иллюстрациями и экспериментами →

Если игровой сервер часто открывает и закрывает короткие соединения с БД или другими серверами, закрытые соединения ещё какое-то время занимают порты, и новые соединения открыть не удаётся.

Почему На каждый запрос открывается и закрывается новое соединение → Следствие Сторона, закрывшая соединение первой, держит порт около 60 секунд (в Linux) в состоянии TIME_WAIT, и свободные порты заканчиваются → На экране Внутренние запросы не проходят: сбои сохранения и ошибки функций

Симптомы
Съеденные действия / роллбэк, Ошибка входа / бесконечная загрузка
Факторы
Потери
У кого
Весь сервер, Только одна функция
Когда
При наплыве игроков
Ответственные
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Серверная инфраструктура
Команда разработки: задачи
Переиспользовать соединения (пул соединений), не открывать и не закрывать соединение на каждый запрос.
Команда инфраструктуры: задачи
Расширить диапазон портов (ip_local_port_range), рассмотреть повторное использование TIME_WAIT для исходящих соединений (tcp_tw_reuse в Linux), следить за числом TIME_WAIT.
Цифры для ориентира
Диапазон портов в Linux по умолчанию (32768–60999) даёт около 28 000 портов. Если открывать к одному и тому же адресу больше 470 новых соединений в секунду, порты заканчиваются. В Windows портов по умолчанию около 16 000 (49152–65535), а TIME_WAIT длиннее, поэтому порты заканчиваются ещё быстрее.
На графике
Упор в лимит (плато) · число сокетов в TIME_WAIT, число неудачных внутренних соединений
Где смотреть
Подсчитать сокеты в TIME_WAIT по адресам назначения через ss -tan state time-wait и найти в логах игрового сервера ошибки connect (EADDRNOTAVAIL)
Подтверждает
Число TIME_WAIT к одному адресату (БД и т. п.) выходит на плато около размера диапазона эфемерных портов (по умолчанию около 28 000), а connect завершается с EADDRNOTAVAIL
Опровергает
Если TIME_WAIT мало, но сбоят только исходящие соединения во внешнюю сеть, это «Лимиты соединений и портов облачного NAT-шлюза»
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Подробнее
60 секунд TIME_WAIT в Linux зашиты в ядро. Если уменьшить похожий по названию tcp_fin_timeout, TIME_WAIT короче не станет.

Источники

  1. IP Sysctl Linux kernel
    ip_local_port_range по умолчанию 32768–60999, параметр tcp_tw_reuse, tcp_fin_timeout: время пребывания в состоянии FIN_WAIT_2
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    TCP_TIMEWAIT_LEN(60*HZ): TIME_WAIT длиной около 60 секунд задан константой ядра
  3. TCP/IP port exhaustion troubleshooting Microsoft
    Динамические порты Windows по умолчанию 49152–65535, закрытое соединение по умолчанию держит порт в TIME_WAIT 4 минуты
  4. ss(8) — Linux manual page iproute2
    Фильтр состояния state time-wait отбирает только сокеты в TIME_WAIT
  5. connect(2) — Linux manual page Linux man-pages
    EADDRNOTAVAIL: соединение не открыть, потому что заняты все порты из диапазона эфемерных портов

Смотрите также

Тот же слой: L7 ОС сервера (ядро)

Причины с тем же симптомом (Съеденные действия / роллбэк) на других слоях

Карточка в основной версии с иллюстрациями и экспериментами