Если у одного игрока с медленным подключением заполнился буфер отправки, а сервер отправляет данные блокирующим способом (вызов не возвращается, пока в буфере не освободится место), поток сервера ждёт этого одного игрока.
Почему Буфер отправки медленного клиента заполнен → Следствие Отправка блокирующая, и поток сервера ждёт, пока в буфере освободится место → На экране У всех, кого обслуживает этот поток, фриз или слоумо
Основной ответственный Команда разработки · Разработка сервера
Команда разработки: задачи
Перейти на неблокирующую отправку, ограничить очередь отправки для каждого клиента, выбрасывать устаревшие обновления.
На графике
Случайные всплески · время тика сервера, Send-Q по соединениям
Где смотреть
Найти через ss -tn соединения, у которых Send-Q (байты без ACK или ещё не отправленные) заполнен на весь буфер отправки, и в момент всплеска времени тика посмотреть в дампе потоков (стеках) игрового сервера, нет ли потоков, застрявших в вызове send
Подтверждает
Когда есть медленное соединение с заполненным Send-Q, обслуживающий его поток стоит в send, и вместе с ним замирают только игроки, которых обслуживает тот же поток
Опровергает
Если остановившийся поток ждёт вне send (на блокировке, в вызове БД), это «Конкуренция за блокировки» или «Синхронные вызовы в игровом потоке»
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Источники
send(2) — Linux manual pageLinux man-pages Если в буфере отправки нет места, send() блокируется, а в неблокирующем режиме сразу возвращает EAGAIN
send function (winsock2.h)Microsoft В Winsock send тоже блокируется при нехватке места в буфере, если сокет не в неблокирующем режиме
net/ipv4/tcp_diag.c (Linux v6.12)Linux kernel Значения Recv-Q и Send-Q в ss: у слушающего сокета это число подключений, ждущих accept, и лимит backlog, у подключённого сокета это байты, ещё не прочитанные приложением, и отправленные байты без ACK