Когда сервер Garry's Mod лагает, причина почти всегда в Lua - один аддон делает слишком много работы каждый tick или каждый tick выдаёт ошибку - или в физике, когда слишком много пропов касаются друг друга. Железо виновато редко, а один только тариф побольше почти никогда это не лечит. Рабочий метод короткий: найдите в консоли повторяющиеся ошибки Lua и исправьте или удалите аддон, который их выдаёт, замерьте время кадра сервера командой stats прямо во время лага, профилируйте хуки аддоном-профилировщиком, чтобы найти дорогой, и делите список аддонов пополам на тестовой копии, если ничто другое не называет виновника. Затем выставьте разумный tickrate, лимиты пропов и ночной перезапуск, чтобы всё так и осталось исправленным. В этом руководстве каждый шаг разобран с командами.
Куда уходит время на сервере Garry's Mod#
Сервер Garry's Mod выполняет игровую симуляцию в одном потоке. Каждый tick - 66 раз в секунду при -tickrate 66, 33 при -tickrate 33 - он обрабатывает физику, логику сущностей и все хуки Lua, зарегистрированные игровым режимом и аддонами, а затем отправляет обновления игрокам. Если работа одного tick занимает больше интервала tick (15 мс при 66 tick), сервер отстаёт, и игроки чувствуют это как откаты, запаздывающие выстрелы и дёргающиеся пропы.
| Источник нагрузки | Типичный симптом | Где смотреть |
|---|---|---|
| Хук Lua с тяжёлой работой каждый tick | Лаг растёт с числом игроков | Профилировщик, бисекция аддонов |
| Ошибка Lua внутри хука | Спам в консоли, постоянный лёгкий лаг | Консоль, лог ошибок |
| Физика: много соприкасающихся пропов | Лаг, когда кто-то строит или рушится куча | Число пропов, настройки физики |
| Net-сообщения: слишком много за раз | Игроки отключаются с ошибками переполнения | Консоль клиента, бисекция аддонов |
| Запросы к базе данных в основном потоке | Скачки при входе, смерти или конце раунда | Аддоны с SQL, размер sv.db |
| Нехватка памяти | Краш через часы или дни | График памяти, 32 или 64 бита |
Порядок важен. Ошибки Lua найти дешевле всего, и они встречаются чаще всего, поэтому начинайте с них. Базовая установка и первый проход диагностики описаны в статье установка сервера Garry's Mod; здесь мы идём глубже.
Чтение ошибок Lua#
Ошибка Lua выводится в консоль сервера с файлом, строкой и трассировкой стека:
[ERROR] addons/coolhud/lua/autorun/server/sv_hud.lua:42: attempt to index a nil value 1. fn - addons/coolhud/lua/autorun/server/sv_hud.lua:42 2. unknown - lua/includes/modules/hook.lua:96Читайте сверху. Первая строка говорит, какой файл и какая строка упали и почему; путь называет аддон (здесь coolhud, а для контента из Workshop - название аддона в Workshop). Стек показывает, что его вызвало: hook.lua означает, что код запущен из хука, а значит, он выполнится и в следующем tick, и в следующем за ним.
Частые сообщения и что они обычно означают:
| Сообщение | Обычная причина |
|---|---|
attempt to index a nil value | Код предполагал, что игрок, сущность или таблица существует, а её нет |
attempt to call a nil value | Не хватает функции из другого аддона или удалённого API |
attempt to compare number with nil | Значение конфига или сетевая переменная так и не были заданы |
Tried to use a NULL entity! | Сущность удалили, пока код ещё её использовал |
bad argument #1 to ... | Передан неверный тип, часто после того, как обновление Garry's Mod что-то изменило |
stack overflow | Бесконечная рекурсия, часто два аддона перехватывают друг друга |
Для производительности важнее всего ошибка внутри хука, который выполняется каждый tick. Сам обработчик ошибок стоит времени, консоль заполняется спамом, а лог растёт. Один сломанный HUD-аддон, выдающий ошибку в хуке Think для каждого игрока, может стоить больше, чем весь остальной список аддонов вместе.
Как получить ошибки, которые можно прочитать потом
Живая консоль на загруженном сервере прокручивается слишком быстро, чтобы её читать. Помогают две настройки:
con_logfile "console.log"lua_log_sv 1con_logfile пишет всё, что выводит консоль, в файл внутри garrysmod/, а lua_log_sv 1 просит сервер логировать ещё и свои ошибки Lua. Оба файла растут; удаляйте или ротируйте их раз в неделю. Какие строки важны, а какие - шум, объясняет статья как читать консоль.
Клиентские ошибки - в HUD, меню и эффектах - происходят на машине каждого игрока и появляются в его консоли, а не в вашей. Если игроки сообщают об ошибках, которых вы никогда не видите, попросите скриншот их консоли после ввода lua_log_cl 1; путь в ошибке всё равно называет аддон.
Исправление или удаление аддона с ошибками#
Когда консоль назвала аддон, есть четыре варианта, в порядке предпочтения:
- Обновите его. Многие ошибки появляются после того, как обновление Garry's Mod изменило API, а автор уже всё исправил. Аддоны из Workshop обновляются сами при перезапуске; старые аддоны в
garrysmod/addons/- нет. - Проверьте на конфликт. Аддон, который работает один и падает при установленном другом, обычно означает, что оба переопределяют одну и ту же функцию или имя хука. Уберите второй и проверьте.
- Исправьте сами. Если вы читаете Lua, файл и строка прямо перед вами. Проверка на nil (
if not IsValid(ent) then return end) исправляет большую долю реальных ошибок. - Удалите его. Заброшенный аддон, выдающий ошибки каждый tick, не стоит того, чтобы его держать. Уберите его из коллекции или удалите его папку.
Не глушите ошибки, оборачивая всё подряд в pcall. Это прячет ошибку, но сохраняет её цену.
Замеры: stats, status и профилировщик#
Нельзя исправить лаг, который вы не измерили. Три инструмента, от самого дешёвого до самого подробного.
stats в консоли сервера выводит загрузку CPU, входящий и исходящий трафик, время работы, число смен карт и частоту кадров сервера. Запускайте во время лага. Если частота кадров ниже tickrate, сервер не успевает - это проблема сервера. Если она равна tickrate, а игроки всё равно жалуются, смотрите на их соединение и на net-сообщения.
status перечисляет игроков с их пингом и потерями. Один игрок с 400 мс и потерями - это маршрут этого игрока; у всех 400 мс - это сервер. Разницу объясняет статья задержка, jitter и потеря пакетов.
Профилировщик показывает, какие функции Lua тратят время. FProfiler - давний аддон-профилировщик для Garry's Mod: установите его, начните запись, пока сервер загружен, остановите через минуту, и он покажет самые дорогие хуки и функции с суммарным и средним временем. Этот список обычно всё решает - наверху один хук из одного аддона, который стоит в десять раз больше всего остального.
Полезны и быстрые проверки через lua_run из консоли сервера:
lua_run print(#ents.GetAll())lua_run print(#player.GetAll())lua_run print(collectgarbage("count"))Первая выводит число сущностей, и на сервере sandbox или DarkRP это говорит, копятся ли пропы. Последняя выводит память Lua в килобайтах; если она часами стабильно растёт и никогда не падает обратно, какой-то аддон теряет таблицы.
Цена аддонов: что делает аддон дорогим#
Некоторые шаблоны стабильно дороги, и если узнавать их в результатах профилировщика, это экономит время:
- Циклы по игрокам или сущностям каждый tick. Хук
ThinkилиTick, который вызываетplayer.GetAll()илиents.FindInSphereи что-то делает с каждым результатом. Дёшево при 10 игроках, дорого при 60. - Таймеры с крошечными интервалами.
timer.Createс задержкой0или0.01, повторяющийся вечно. Фактически ещё один хук на каждый tick. - Сеть в хуках. Отправка net-сообщений всем игрокам каждый tick или пересылка больших таблиц. Стоит и полосы, и CPU и вызывает отключения из-за переполнения.
- Доступ к файлам и SQL в хуках. Чтение или запись файлов либо выполнение
sql.Queryк локальной базе SQLite внутри частого хука. И то и другое блокирует игровой поток. - Сущности с тяжёлой физикой. Транспорт, верёвки, конструкции на wire и всё, что создаёт много физических объектов.
Когда ничего очевидного не видно, делите пополам. Сделайте копию сервера на тестовом экземпляре, уберите половину аддонов и замерьте под той же нагрузкой. Продолжайте делить, пока лаг не будет следовать за одним аддоном. Это утомительно, и это единственный метод, который работает всегда.
Типичный случай от начала до конца
Ролевой сервер нормально работает с двадцатью игроками и тормозит при сорока. В консоли ничего. stats в час пик показывает, что частота кадров сервера падает до двадцати с небольшим при tickrate 33, то есть сервер действительно отстаёт. Минутная запись профилировщика ставит наверх одну функцию: хук аддона, связанного с HUD, который каждый tick перебирает всех игроков и для каждого перебирает все сущности, чтобы найти ближайшую дверь. Сорок игроков на несколько тысяч сущностей, 33 раза в секунду.
Ничего в этом хуке не было сломано. Он работал, не выдавал ошибок и при двадцати игроках стоил миллисекунду на tick. При сорока игроках цена выросла вчетверо, потому что оба списка удвоились. Решением было запускать ту же проверку раз в секунду, а не каждый tick, - конфиг аддона это позволял, но никто туда не смотрел. Частота кадров вернулась к tickrate, а тариф не поменялся.
Так выглядит большинство проблем производительности Garry's Mod: не баг, а работа, которая растёт как игроки, умноженные на сущности, спрятанная в аддоне, который при запуске казался безобидным. Профилировщик находит её за минуты; гадание занимает недели.
Физика, пропы и лимиты#
Физика тоже обрабатывается каждый tick и дорожает нелинейно: сто лежащих неподвижно пропов дёшевы; сто пропов, сваленных в кучу и касающихся друг друга, - нет, потому что каждый контакт разрешается каждый tick. На серверах sandbox и ролевых серверах худший лаг обычно идёт от конструкции одного игрока или намеренно собранной кучи пропов.
sbox_maxprops 150sbox_maxragdolls 5sbox_maxvehicles 2sbox_maxeffects 50sbox_maxballoons 10sbox_maxthrusters 20sbox_noclip 1Эти лимиты действуют на каждого игрока. Держите их настолько низкими, насколько позволяет ваш режим; сервер sandbox с sbox_maxprops 1000 и тридцатью игроками теоретически может держать тридцать тысяч пропов. Включите в админ-моде или отдельном аддоне очистку пропов при отключении игрока и подумайте об аддоне против крашей, который замораживает пропы, когда слишком многие сталкиваются одновременно. TTT и другие раундовые режимы очищают всё каждый раунд, и им это нужно гораздо меньше. Этот режим отдельно описан в статье руководство по серверу TTT.
Tickrate, гибернация и память#
-tickrate в строке запуска задаёт, сколько tick в секунду выполняет сервер. 66 плавнее; 33 вдвое снижает цену на tick и вполне подходит для ролевых серверов и sandbox, где точность прицеливания важна меньше. Задавайте его явно, а не полагайтесь на значение по умолчанию.
| Игровой режим | Разумный tickrate | Почему |
|---|---|---|
| Sandbox, DarkRP, ролевые режимы | 33 | Много сущностей, прицеливание менее важно |
| TTT, Murder, Prop Hunt | 33-66 | Раундовые, умеренное число сущностей |
| Режимы, ориентированные на бой | 66 | Важны прицеливание и регистрация попаданий |
Повышение tickrate примерно удваивает цену CPU на tick и ничего не меняет для сервера, который уже отстаёт. Сначала уменьшите нагрузку, затем поднимайте частоту, если есть запас. Развёрнутый аргумент - в статье что на самом деле означает tick rate.
Пустой сервер Garry's Mod по умолчанию уходит в гибернацию и почти не использует CPU. sv_hibernate_think 1 заставляет его продолжать работу и без игроков, что нужно некоторым аддонам; если ваш простаивающий сервер стабильно расходует CPU, проверьте, не задана ли эта настройка или не крутит ли какой-то аддон таймер в любом случае.
Проблемы с памятью выглядят иначе. Стандартный сервер Garry's Mod - 32-битный процесс, поэтому он может адресовать только около 4 ГБ, сколько бы ни было на тарифе; большие коллекции упираются в этот потолок и падают с ошибками нехватки памяти, хотя график выглядит нормально. Бета-ветка x86-64 снимает это ограничение ценой того, что всем бинарным модулям нужны 64-битные сборки. Локальная база SQLite, garrysmod/sv.db, - ещё одна медленная утечка: некоторые аддоны пишут в неё постоянно, а файл в сотни мегабайт замедляет каждый запрос. Время от времени проверяйте её размер и чистите или переносите данные, которые туда складывают аддоны.
Перезапуски, краши и как удержать результат#
Даже хорошо настроенный сервер Garry's Mod за несколько дней накапливает сущности, таймеры и память Lua. Ночной перезапуск в пустой час держит время кадра ровным и ничего не стоит. На RE:NODE вкладка Schedules выполняет его по cron-выражению, с необязательной командой-предупреждением за несколько минут. О выборе времени рассказывает статья расписания перезапусков, которые помогают.
Краши - отдельная от лагов проблема. Ошибка Lua сервер не роняет; краш вызывает бинарный модуль, физический взрыв, потолок памяти 32-битного процесса или остановка процесса на лимите памяти тарифа. На RE:NODE сервер, достигший лимита памяти, останавливается и перезапускается начисто, а не уходит в своп, а наблюдатель считает неожиданные перезапуски - три за час ставят предупреждение на страницу сервера и автоматически открывают тикет, так что цикл крашей не останется незамеченным. Различить эти случаи помогает статья почему игровой сервер постоянно перезапускается.
Решение проблем#
Консоль заполнена одной и той же ошибкой Lua. Один аддон в хуке. Прочитайте путь в первой строке, обновите или удалите этот аддон и перезапустите сервер.
Лаг только когда сервер заполнен. Нагрузка на игрока. Профилируйте в час пик; ищите хуки, перебирающие игроков.
Скачки лага при входе игрока. Аддоны работают с базой данных или файлами в PlayerInitialSpawn, или sv.db слишком большой. Профилируйте вход.
Игроки отключаются с «reliable channel overflowed». Аддон отправляет слишком много за один раз, обычно при появлении. Убирайте аддоны, пока это не прекратится; консоль клиента показывает последнее полученное сообщение.
Сервер падает через несколько часов при свободной памяти. Адресное пространство 32-битного процесса. Урежьте аддоны или перейдите на 64-битную ветку с соответствующими модулями.
Простаивающий сервер расходует CPU. sv_hibernate_think 1 или таймер аддона, работающий без игроков.
FAQ#
Вызывают ли ошибки Lua лаги?
Ошибка, случившаяся один раз, неважна. Ошибка внутри хука, который выполняется каждый tick, важна, потому что обработчик ошибок срабатывает каждый раз, а консоль и лог заполняются. Сначала исправляйте повторяющиеся ошибки.
Какой tickrate ставить серверу Garry's Mod?
33 для sandbox и ролевых серверов, 33-66 для раундовых режимов, 66 для режимов, ориентированных на бой. Пропишите его явно в строке запуска и поднимайте, только когда у сервера есть запас CPU в час пик.
Исправит ли лаг тариф побольше?
Только если серверу действительно не хватает CPU или памяти после того, как проблемы с аддонами исправлены. Один дорогой хук или куча сталкивающихся пропов будут лагать на любом железе. Сначала замерьте, потом выбирайте размер.
Как найти аддон, который вызывает лаг?
Найдите в консоли повторяющиеся ошибки, затем запустите профилировщик, например FProfiler, пока сервер загружен. Если ни то ни другое не называет виновника, уберите половину аддонов на тестовой копии и замерьте, повторяя, пока лаг не будет следовать за одним аддоном.
Стоит ли запускать 64-битный сервер Garry's Mod?
Если ваш сервер падает с ошибками памяти, хотя у тарифа есть свободная память, - да. Сначала проверьте, что у каждого используемого бинарного модуля есть 64-битная сборка.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.