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

Анатомия игровых лагов › L8 Сокеты и протоколы

Алгоритм Нейгла + отложенный ACK Nagle + delayed ACK (TCP_NODELAY off)

ID причины sk-nagle · Основной ответственный Команда разработки · Разработка сервера · Совместно Команда разработки · Разработка клиента

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

Алгоритм Нейгла, который копит мелкие пакеты перед отправкой, и отложенный ACK, который придерживает подтверждения, мешают друг другу, и каждое сообщение, записанное по частям, задерживается на 40–200 ms.

Почему Мелкие сообщения пишутся по частям без включённого TCP_NODELAY → Следствие Отправитель ждёт ACK, а получатель отправляет ACK с задержкой → На экране Пинг низкий, но все действия одинаково запаздывают: задержка ввода

Симптомы
Задержка ввода
Факторы
Задержка
У кого
Весь сервер, Только у меня
Когда
Всегда, При определённом действии
Ответственные
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда разработки · Разработка клиента
Команда разработки: задачи
Сервер: включить TCP_NODELAY, собирать сообщения за тик и записывать их за один раз. На отключение отложенного ACK у получателя не полагаться (TCP_QUICKACK в Linux действует недолго, в Windows нужно править реестр на каждом ПК): игра не может надёжно этим управлять. Клиент: включить TCP_NODELAY, собирать сообщения за кадр и записывать их за один раз.
Цифры для ориентира
Отложенный ACK в Linux обычно 40 ms (в зависимости от ситуации до 200 ms). В старых версиях Windows было 200 ms, в современных 40 ms (в стандартном шаблоне Windows Server 2019 тоже 40 ms). Задержку ACK определяет ОС получателя, поэтому, если сервер с включённым Nagle отправляет сообщения по частям, задержка в зависимости от ПК игрока может составлять 40–200 ms.
На графике
Высоко с самого начала · время отклика на действие (RTT внутри игры)
Где смотреть
Посмотреть в захвате пакетов на стороне сервера (tcpdump, Wireshark) интервалы между запросами и ответами и проверить, включает ли код сервера и клиента TCP_NODELAY
Подтверждает
Пинг низкий, но между мелкими пакетами повторяются паузы около 40 ms (в старых версиях Windows 200 ms), и каждая пауза заканчивается сразу после прихода ACK от другой стороны. С TCP_NODELAY паузы исчезают
Опровергает
Если интервал ответа близок к пингу, причина в другом. Если игровой сервер сам поздно формирует ответ, дело в обработке на сервере («Затор в очереди сообщений»)
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)

Источники

  1. RFC 9293: Transmission Control Protocol (TCP) IETF
    Пока есть данные без ACK, алгоритм Нейгла копит мелкие порции. Должна быть возможность отключить его для каждого соединения. Отложенный ACK меньше 0,5 с. Описана проблема их взаимодействия
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    Отложенный ACK в Linux: минимум TCP_DELACK_MIN (HZ/25 = 40 ms), максимум TCP_DELACK_MAX (HZ/5 = 200 ms)
  3. TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft
    Таймаут отложенного ACK в Windows по умолчанию изменён на 40 ms (доклад 2017 года)
  4. TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft
    Шаблон Server 2019: DelayedAckTimeout 40 ms, MaxSynRetransmissions 2, InitialRto 3 000 ms
  5. Design issues - Sending small data segments over TCP with Winsock Microsoft
    Старый TCP в Windows при получении данных запускал таймер отложенного ACK на 200 ms, а Nagle был включён по умолчанию, поэтому мелкие пакеты ждали ACK. Решение: TCP_NODELAY

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

Тот же слой: L8 Сокеты и протоколы

Причины с тем же симптомом (Задержка ввода) на других слоях

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