Тюнинг сетевого стека Linux для игрового сервера (sysctl)
Сервер держит 60+ игроков, CPU и RAM в запасе, а тикрейт всё равно проседает и в логах изредка мелькают обрывы соединений — знакомая картина. Часто дело не в игровом процессе, а в том, что сетевой стек Linux настроен на "среднего" пользователя, а не на сервер, который принимает тысячи UDP-пакетов в секунду от полусотни клиентов одновременно. В этой статье — какие параметры sysctl реально влияют на игровой сервер, как их менять безопасно и как проверить, что тюнинг вообще сработал.
Содержание
Почему дефолтных настроек ядра не хватает
Дистрибутивы Linux по умолчанию настроены под универсальный сценарий: немного соединений, умеренный трафик, экономия памяти. Игровой сервер — это другая нагрузка: десятки-сотни клиентов шлют небольшие пакеты с высокой частотой (у шутеров вроде CS2 или ARK: Survival Ascended — десятки раз в секунду на игрока), и ядру нужно успевать их принимать, буферизовать и отдавать процессу игры без потерь.
Когда буферов не хватает, происходит одно из трёх: пакеты дропаются на уровне сетевой карты (растёт RX packets dropped), очередь соединений переполняется и новые подключения отваливаются с таймаутом, либо conntrack-таблица (если включён iptables/nftables с state-трекингом) забивается под завязку и роняет новые UDP-сессии. Игрок это видит как рывки, "телепорты", разрывы связи при заходе на сервер в пиковые часы — притом что по CPU/RAM всё в порядке. Отдельно от сетевого стека стоит проверять и сам движок — если после тюнинга sysctl лаги остались, дело может быть в самом мире или плагинах, а не в сети.
Важная оговорка: не все игровые протоколы одинаковы. Source-движок (CS2, TF2), Rust, ARK, большинство shooter/survival-серверов работают поверх UDP — там важны буферы net.core и conntrack. Minecraft Java Edition и RCON-протокол работают через TCP — там дополнительно играют роль TCP-специфичные параметры (tcp_rmem, tcp_max_syn_backlog, congestion control). Ниже разберём оба случая.
Буферы приёма и отправки: net.core.rmem/wmem
Первое, на что стоит смотреть — размер буферов сокетов на уровне ядра. Это память, которую ядро выделяет под входящие и исходящие пакеты, пока их не заберёт (или не отправит) приложение.
# /etc/sysctl.d/99-game-server.conf
# Максимальный размер буфера приёма/отправки на сокет (в байтах)
net.core.rmem_max = 26214400
net.core.wmem_max = 26214400
# Буфер по умолчанию для новых сокетов
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
# Диапазон для TCP: минимум, дефолт, максимум (в байтах)
net.ipv4.tcp_rmem = 4096 1048576 26214400
net.ipv4.tcp_wmem = 4096 1048576 26214400
# Минимальные буферы для UDP-сокетов
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384
Частая ошибка — поднять только rmem_max, но не поднять rmem_default. Приложение (игровой сервер) при создании сокета без явного SO_RCVBUF получит именно значение по умолчанию, а не максимум — так что «прибавка» из rmem_max просто не используется, пока сама игра явно не запросит буфер побольше через setsockopt. Большинство игровых серверов (Source-движок, SteamCMD-сборки, ARK) это не делают, поэтому реальный выигрыш даёт именно rmem_default/wmem_default.
Значения выше — это ориентир для сервера на 20-60 игроков, не измеренный бенчмарк: под конкретную игру и онлайн их стоит подбирать опытным путём, отслеживая счётчики ошибок (см. раздел про проверку ниже).
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверОчередь соединений и backlog
Отдельная группа параметров отвечает не за объём данных, а за очередь: сколько пакетов/соединений ядро готово держать в ожидании, пока процесс их не заберёт.
# Очередь пакетов на входе сетевой карты до того, как их заберёт ядро
net.core.netdev_max_backlog = 16384
# Очередь TCP-соединений, ожидающих accept() — важно для RCON и веб-панели
net.core.somaxconn = 4096
# Очередь "полуоткрытых" TCP-соединений (SYN получен, ACK ещё нет)
net.ipv4.tcp_max_syn_backlog = 4096
netdev_max_backlog особенно критичен на серверах с высоким пакетрейтом: если процессор не успевает разгребать входящую очередь (актуально на бюджетных VPS с 1-2 vCPU при большом онлайне), пакеты дропаются ещё до попадания в TCP/UDP-стек, и это не видно в логах игры — только в сетевой статистике. somaxconn и tcp_max_syn_backlog играют роль там, где много TCP-подключений разом: например, прокси-сеть на BungeeCord/Velocity, где backend-серверы держат десятки одновременных соединений от прокси, или веб-панель управления сервером под нагрузкой.
Conntrack: узкое место, которое не видно по CPU
Если на сервере включён iptables или nftables с трекингом состояний (а по умолчанию это почти всегда так — даже стандартные правила для проброса портов создают conntrack-записи), у ядра есть таблица активных соединений с ограниченным размером. Каждое новое UDP "соединение" (условное — UDP не имеет состояния, но conntrack всё равно трекает пары адрес:порт) создаёт запись в этой таблице.
# Проверить текущий размер таблицы и лимит
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
# Поднять лимит (пример для сервера с 2+ ГБ RAM)
net.netfilter.nf_conntrack_max = 262144
# Таймаут для UDP-сессий по умолчанию короче TCP — на игровом
# трафике с постоянным потоком мелких пакетов лучше не занижать
net.netfilter.nf_conntrack_udp_timeout = 60
net.netfilter.nf_conntrack_udp_timeout_stream = 180
Симптом переполненной conntrack-таблицы — сообщения nf_conntrack: table full, dropping packet в dmesg или journalctl -k. Это одна из самых незаметных проблем: CPU свободен, RAM свободна, а новые игроки не могут зайти на сервер именно в момент, когда онлайн максимальный — то есть таблица уже забита старыми записями. Если у вас есть отдельный firewall с white-list/geo-фильтрацией, стоит свериться заодно с настройкой портов и файрвола для игрового сервера — иногда причина не в лимите таблицы, а в избыточно широких правилах, которые трекают трафик, который вообще не нужно трекать.
Модуль nf_conntrack может быть не загружен, если firewall работает в режиме без stateful-инспекции — тогда параметры выше просто не существуют в /proc/sys, и это нормально: проверьте lsmod | grep nf_conntrack перед тем как что-то менять.
TCP-тюнинг: RCON, веб-панель и Minecraft
Для протоколов на базе TCP (RCON, встроенные веб-панели, Minecraft Java) актуален отдельный набор параметров — они влияют на то, как быстро закрываются "зависшие" соединения и насколько агрессивно TCP разгоняет передачу данных.
# Быстрее закрывать соединения в состоянии FIN_WAIT2
net.ipv4.tcp_fin_timeout = 30
# Переиспользовать TIME_WAIT сокеты для новых соединений
# (безопасно для исходящих соединений, осторожно на публичных
# серверах за NAT с большим числом клиентов с одного IP)
net.ipv4.tcp_tw_reuse = 1
# Не сбрасывать congestion window после простоя соединения —
# полезно для RCON-клиентов, которые подключаются нечасто
net.ipv4.tcp_slow_start_after_idle = 0
# Современный congestion control и планировщик очереди пакетов
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
BBR даёт заметный эффект в первую очередь на линках с потерями пакетов или большим RTT (например, US-локация для игроков из Европы), меньше — на локальном/региональном хостинге с низким пингом. Перед включением проверьте, что модуль доступен: sysctl net.ipv4.tcp_available_congestion_control должен содержать bbr — на части урезанных ядер (некоторые OpenVZ/LXC-контейнеры от бюджетных хостеров) BBR недоступен, потому что требует модуля ядра, а не namespace-изоляции. На KVM-VPS с полным доступом к своему ядру таких ограничений обычно нет.
Как применить, проверить и не сломать сервер
Не редактируйте /etc/sysctl.conf напрямую — заведите отдельный файл, чтобы легко откатить изменения:
sudo nano /etc/sysctl.d/99-game-server.conf
# вставить нужные параметры
# Применить без перезагрузки
sudo sysctl -p /etc/sysctl.d/99-game-server.conf
# Проверить, что значение реально применилось
sysctl net.core.rmem_max
После применения — не верьте на слово, проверяйте счётчики ошибок до и после под реальной нагрузкой:
# Общая статистика ошибок по протоколам
netstat -su | grep -i -E "error|dropped|overflow"
# Более детальная статистика (пакет net-tools или iproute2)
nstat -az | grep -i -E "drop|overflow|retrans"
# Текущее состояние сокетов и очередей
ss -s
Если после суток работы под нагрузкой счётчики packet receive errors или RcvbufErrors продолжают расти — буферов всё ещё не хватает, поднимайте дальше. Если счётчики стоят на месте — можно не трогать, лишний запас памяти под буферы ничего не даёт, только тратит RAM впустую. Держите тюнинг синхронизированным с наблюдением за трафиком в целом — статья про мониторинг сетевого трафика игрового сервера объясняет, на какие метрики смотреть в динамике, а не только в моменте.
Типичные грабли
- Правите
/etc/sysctl.conf, а после перезагрузки настройки слетают. Проверьте, не перезаписывает ли их другой файл в/etc/sysctl.d/с более высоким приоритетом (файлы применяются по алфавиту, последний побеждает) — назовите свой файл с высоким номером, например99-game-server.conf. - Меняете
rmem_max, но не трогаетеrmem_default. Как объяснялось выше — большинство игровых серверов не запрашивают буфер явно, и без дефолта максимум просто не используется. - Тюните sysctl внутри Docker-контейнера. Часть параметров
net.core/net.ipv4— сетевые namespace-параметры, их нужно менять на хосте (или через--sysctlпри запуске контейнера с нужными правами), а не внутри контейнера — оттуда изменение либо не применится, либо потребует--privileged. - Ставите conntrack-лимит больше, чем позволяет RAM. Каждая запись в таблице занимает реальную память (порядка 300-350 байт, зависит от версии ядра) — на сервере с 1-2 ГБ RAM неограниченно раздувать
nf_conntrack_maxне стоит, считайте от доступной памяти. - Забываете про ограничения хостера. На части бюджетных тарифов с виртуализацией на базе контейнеров (не KVM) часть параметров
/proc/sys/net/доступна только на чтение — еслиsysctl -wпадает сPermission denied/Read-only file system, дело не в синтаксисе, а в виртуализации, и поможет только тариф с полным доступом к ядру. - Меняете параметры "на глаз" без теста под нагрузкой. Высокий пинг у всех игроков сразу не всегда решается sysctl — иногда причина на стороне провайдера или маршрутизации, разбор частых причин есть в статье почему высокий пинг у всех игроков одновременно.
Нужен игровой сервер?
MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.
Создать серверЧастые вопросы
Нужно ли это на сервере до 10-15 игроков?
Почти наверняка нет — дефолтных настроек ядра хватает с большим запасом. Тюнинг sysctl имеет смысл обсуждать начиная примерно с 30-40 одновременных игроков или при явных признаках потерь пакетов (см. раздел про проверку).
Можно ли сломать сервер неправильными значениями sysctl?
Напрямую — сложно: большинство параметров просто перестают давать эффект при неудачных значениях, а не роняют сеть. Риск реален только если сильно занизить буферы (тогда соединения начнут рваться чаще, чем до тюнинга) — поэтому меняйте по одному параметру и проверяйте счётчики, а не весь набор разом.
Помогает ли это против DDoS?
Нет, sysctl-тюнинг про пропускную способность легитимного трафика, а не про фильтрацию вредоносного — от волюметрических атак это не защитит, тут нужна отдельная защита на уровне сети хостера.
Разные значения нужны для Minecraft и для CS2/Rust?
Да: для Minecraft (TCP) в приоритете tcp_rmem/tcp_wmem, tcp_max_syn_backlog, congestion control; для UDP-игр (CS2, Rust, ARK) — net.core.rmem/wmem, netdev_max_backlog и лимиты conntrack. Общие параметры (rmem_max/wmem_max) полезны в обоих случаях.
Сохранятся ли настройки после переезда на другой сервер?
Нет, sysctl — параметры конкретной машины/ядра, при миграции их нужно применить заново на новом хосте. Если параллельно переносите сам мир, см. миграцию сервера к другому хостеру без потери мира.