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

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

Нехватка буферов сокетов в ядре Small socket buffers

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

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

Если буферы приёма и отправки маленькие, то при всплеске трафика принятые по UDP пакеты отбрасываются, а отправка по TCP встаёт, потому что в буфере нет места.

Почему SO_SNDBUF и SO_RCVBUF оставлены по умолчанию или слишком малы → Следствие При всплеске трафика или короткой остановке принимающего потока буфер приёма UDP переполняется и пакеты выбрасываются, а TCP ждёт, пока в буфере отправки освободится место → На экране Телепортация (потери UDP) или перемотка (ожидание TCP)

Симптомы
Телепортация, Перемотка
Факторы
Потери, Остановка
У кого
Весь сервер
Когда
При наплыве игроков
Ответственные
Основной ответственный Команда инфраструктуры · Серверная инфраструктура · Совместно Команда разработки · Разработка сервера
Команда разработки: задачи
Задавать в коде размер буферов под трафик (SO_SNDBUF, SO_RCVBUF). Для TCP учитывать, что явная установка размера отключает автонастройку буферов в Linux. Не делать буферы слишком большими: в них копятся устаревшие данные и растёт задержка. Не допускать остановок принимающего потока.
Команда инфраструктуры: задачи
Настроить пределы ядра (rmem_max, wmem_max: размер буфера, заданный в коде, тоже не может их превысить) и значение по умолчанию (rmem_default), следить за счётчиком переполнений буфера (RcvbufErrors).
Цифры для ориентира
Буфер приёма UDP в Linux по умолчанию около 208 KB. Даже маленький пакет занимает в памяти ядра намного больше своего реального размера, поэтому буфер заполняют уже десятки или сотни пакетов. На сервере, который принимает 100 000 пакетов в секунду, буфер переполняется, если принимающий поток остановится всего на несколько ms.
На графике
Случайные всплески · переполнения буфера приёма UDP (UdpRcvbufErrors)
Где смотреть
Посмотреть прирост UdpRcvbufErrors в nstat -az и skmem в ss -uamn (rb: размер буфера приёма, d: число пакетов, отброшенных до попадания в сокет). Для TCP проверить в skmem из ss -tm, не дошла ли память очереди отправки (w) до размера буфера отправки (tb)
Подтверждает
В моменты всплесков трафика или остановок принимающего потока растёт UdpRcvbufErrors (или d у сокета), а rb около значения по умолчанию (примерно 208 KB). В TCP w упирается в tb, и send блокируется
Опровергает
Если счётчик не растёт, а потери есть, дело на уровне NIC («Слишком маленький кольцевой буфер») или на участке сети
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)

Источники

  1. socket(7) — Linux manual page Linux man-pages
    Значения SO_RCVBUF и SO_SNDBUF по умолчанию берутся из rmem_default и wmem_default, пределы из rmem_max и wmem_max. Ядро удваивает заданное значение
  2. include/net/sock.h (Linux v6.18) Linux kernel
    Буфер сокета по умолчанию определён как 256 пакетов по 256 байт с учётом накладных расходов sk_buff (SKB_TRUESIZE(256)×256). Даже маленький кадр учитывается как sk_buff+MTU (около 208 KB: расчётное значение для x86-64)
  3. IP Sysctl Linux kernel
    tcp_rmem, tcp_wmem: если явно задать SO_RCVBUF или SO_SNDBUF, автонастройка размера буфера для этого сокета отключается
  4. net/ipv4/udp.c (Linux v6.12) Linux kernel
    Если очередь приёма UDP превышает размер буфера сокета, пакет сразу отбрасывается и растёт RcvbufErrors
  5. net/ipv4/proc.c (Linux v6.12) Linux kernel
    Имена счётчиков, которые показывает nstat: RcvbufErrors и SndbufErrors в группе Udp
  6. ss(8) — Linux manual page iproute2
    skmem в выводе -m: rb (размер буфера приёма), tb (размер буфера отправки), w (память очереди отправки), d (число пакетов, отброшенных до попадания в сокет)

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

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

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

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