Miami RP Project СЕРВЕР MTA:SA ONLINE СЕРВЕР GTA 5 RAGE MP В РАЗРАБОТКЕ ЗАПУСК MTA RAGE MP: в разработке

Оптимизация сервера CRMP — мод, MySQL, нагрузка и память

Сегодня Обновлено: Сегодня 0.0 (0)
Оптимизация сервера CRMP — мод, MySQL, нагрузка и память
Категория Оптимизация сервера CRMP и игрового мода Опубликовано Сегодня Обновлено Сегодня Просмотров 3

Оптимизация сервера CRMP начинается не с уменьшения графики или постоянных перезапусков, а с поиска конкретного источника нагрузки. Зависания могут вызывать тяжёлые циклы Pawn, слишком частые таймеры, синхронная работа с файлами, медленные MySQL-запросы, несовместимые плагины, большое количество динамических объектов или постепенное накопление неосвобождённых ресурсов.

Правильная оптимизация должна проводиться по измеримым показателям. Сначала фиксируется нормальная работа сервера, затем воспроизводится проблема, измеряются CPU, память, задержки запросов и время выполнения функций. После этого изменяется один компонент и повторяется тест.

В руководстве разобраны оптимизация игрового мода CRMP, серверных скриптов, MySQL-запросов и плагинов, снижение нагрузки на VPS, устранение зависаний, поиск утечек памяти и проверка результата под нагрузкой.

Обслуживание, журналы и резервные копии сервера:

Администрирование сервера CRMP

Настройка плагинов и устранение ошибок загрузки:

Установка и настройка плагинов CRMP

Настройка и диагностика базы данных:

Подключение MySQL к серверу CRMP

Что означает оптимизация сервера CRMP

Оптимизация — это уменьшение времени выполнения операций и потребления ресурсов без нарушения игровой логики.

Основные цели

  • стабильная работа игрового цикла;
  • отсутствие длительных зависаний;
  • предсказуемое потребление памяти;
  • быстрая загрузка аккаунтов;
  • своевременное сохранение данных;
  • снижение нагрузки на CPU;
  • уменьшение количества запросов MySQL;
  • устранение постепенного ухудшения работы;
  • стабильность при увеличении онлайна.

Оптимизация не должна приводить к

  • потере данных;
  • отключению важных проверок;
  • ухудшению синхронизации;
  • исчезновению объектов;
  • редкому сохранению критических операций;
  • ослаблению античита;
  • скрытию ошибок постоянными перезапусками.

Главный принцип: сначала измерить проблему, затем исправить её и повторно измерить результат.

Какие виды задержек встречаются на CRMP

Серверный фриз

Все игроки одновременно замечают остановку команд, транспорта, таймеров и других игровых систем. Обычно причина находится в Pawn-коде, плагине, синхронной операции или перегруженном VPS.

Высокий сетевой пинг

Игроки продолжают двигаться, но действия приходят с задержкой. Причиной может быть маршрут сети, перегруженный канал или слишком частая синхронизация.

Задержка MySQL

Игровой мир работает, но долго открываются аккаунты, дома, бизнесы, инвентарь или административные журналы.

Постепенное замедление

После запуска сервер работает нормально, но через несколько часов или дней увеличиваются память, количество объектов, таймеров или открытых ресурсов.

Локальная проблема игрока

Зависания наблюдаются только у одного пользователя. Причина может находиться в клиентской сборке, интернете, большом количестве объектов в одной зоне или слабом компьютере.

Кратковременные пики

Сервер зависает во время общего сохранения, загрузки организаций, перезапуска систем или выполнения тяжёлой административной команды.

Фиксация исходных показателей

До изменения кода запишите показатели нормально работающего сервера.

Зафиксируйте

  • средний онлайн;
  • максимальный онлайн;
  • загрузку CPU;
  • потребление оперативной памяти;
  • использование swap;
  • размер базы данных;
  • количество запросов в минуту;
  • время входа игрока;
  • время сохранения аккаунта;
  • размер server_log.txt;
  • время работы до появления проблемы.

Пример журнала измерений

Дата: 31.07.2026
Онлайн: 42 игрока
CPU процесса: 38%
Память RSS: 612 МБ
Swap: 0 МБ
Вход аккаунта: 180 мс
Общее сохранение: 1,8 секунды
Ошибки MySQL: отсутствуют
Время работы: 14 часов

Повторите измерения

Проверяйте показатели:

  • сразу после запуска;
  • через один час;
  • при среднем онлайне;
  • при максимальном онлайне;
  • перед зависанием;
  • после исправления.

Создание тестовой среды

Тестовая сборка должна содержать

  • копию игрового мода;
  • копию плагинов;
  • отдельный server.cfg;
  • другой игровой порт;
  • отдельную базу MySQL;
  • тестовые аккаунты;
  • отдельные журналы;
  • закрытый доступ по паролю.

Не подключайте тестовый сервер к рабочей базе

Две сборки могут одновременно изменять одни аккаунты, транспорт и имущество.

Создание копии базы

mysqldump \
--single-transaction \
-u crmp_user \
-p \
crmp_server \
> crmp-test.sql

Импорт в отдельную базу

mysql \
-u crmp_test_user \
-p \
crmp_test \
< crmp-test.sql

Используйте отдельный порт

port 8905
password ТЕСТОВЫЙ_ПАРОЛЬ

Как найти настоящее узкое место

Высокий CPU процесса CRMP

Проверяйте Pawn-циклы, таймеры, callbacks, стриминг и нативные плагины.

Высокий CPU MySQL

Проверяйте медленные запросы, индексы, частые UPDATE и полное сканирование таблиц.

Память процесса постоянно растёт

Проверяйте динамические объекты, таймеры, текстовые элементы, кэш плагинов и версии нативных библиотек.

Высокий I/O диска

Проверяйте журналы, частую запись INI-файлов, дампы, swap и MySQL.

Проблема появляется при входе игроков

Проверяйте загрузку аккаунтов, имущества, динамических объектов и количество последовательных SQL-запросов.

Проблема появляется при общем сохранении

Проверяйте одновременные UPDATE для всех игроков, синхронные операции и слишком большой объём данных.

Диагностика нагрузки на процессор

Просмотр процессов Linux

top

Более удобный монитор

htop

Поиск процесса CRMP

ps aux \
| grep -E "samp|crmp" \
| grep -v grep

Подробные данные процесса

ps -o \
pid,ppid,%cpu,%mem,rss,vsz,etime,cmd \
-p PID

Наблюдение каждую секунду

pidstat \
-p PID \
1

Проверьте

  • постоянную загрузку одного ядра;
  • пики в определённое время;
  • рост нагрузки вместе с онлайном;
  • пик при сохранении;
  • пик при подключении игрока;
  • пик после запуска filterscript;
  • другие процессы, забирающие CPU.

Учитывайте одно ядро

Если процесс использует около 100% одного логического ядра, это уже может быть пределом для основной игровой логики, даже если общий CPU восьмиядерного VPS показывает небольшое значение.

Диагностика оперативной памяти

Общая память VPS

free -h

Память процесса

ps -o \
pid,rss,vsz,%mem,etime,cmd \
-p PID

Карта памяти процесса

pmap -x PID \
| tail -n 20

Следите за RSS

RSS показывает объём физической памяти, который фактически использует процесс.

Записывайте значение периодически

while true
do
 date
 ps -o pid,rss,vsz,%mem,etime \
 -p PID

 sleep 300
done

Признаки возможной утечки

  • память постоянно растёт при одинаковом онлайне;
  • после выхода игроков память не стабилизируется;
  • рост связан с конкретной командой;
  • каждый рестарт filterscript увеличивает память;
  • после нескольких загрузок объектов появляется резкий рост;
  • swap постепенно заполняется.

Проверка нагрузки на диск

Свободное место

df -h

Свободные inode

df -i

Нагрузка диска

iostat -xz 1

Общая активность системы

vmstat 1

Размер каталогов

du -sh \
/home/crmp/server/*

Поиск больших файлов

find /home/crmp \
-type f \
-size +100M \
-print

Источники лишней записи

  • слишком подробный server_log.txt;
  • логирование каждого движения игрока;
  • частое сохранение INI;
  • общий MySQL-журнал;
  • частые резервные дампы;
  • core-файлы после падений;
  • активное использование swap.

Проверка сети и игрового порта

Просмотр UDP-портов

sudo ss -lunp

Сетевой трафик интерфейсов

sar -n DEV 1

Проверка потерь до сервера

ping IP_СЕРВЕРА

Диагностика маршрута

mtr IP_СЕРВЕРА

Отделяйте сетевую проблему от серверной

  • если зависают все игровые системы одновременно — проверяйте сервер;
  • если один игрок имеет высокий пинг — проверяйте его маршрут;
  • если проблема появляется только вечером — проверяйте канал и хостинг;
  • если растёт исходящий трафик — проверяйте интервалы синхронизации;
  • если порт недоступен — проверяйте процесс и firewall.

Измерение времени выполнения Pawn-кода

Для поиска медленных участков можно временно измерять время функций.

Простой пример

new startedAt = GetTickCount();

LoadPlayerInventory(playerid);

new elapsedTime =
 GetTickCount() - startedAt;

if (elapsedTime > 10)
{
 printf(
 "[PERFORMANCE] LoadPlayerInventory: %d ms",
 elapsedTime
 );
}

Измеряйте

  • вход игрока;
  • загрузку персонажа;
  • загрузку транспорта;
  • общее сохранение;
  • обработку команд;
  • создание объектов;
  • работу таймеров;
  • античит-проверки;
  • административные отчёты.

Не оставляйте чрезмерный отладочный вывод

Если измерение выполняется сотни раз в секунду, постоянный printf сам создаст нагрузку. Записывайте только превышение установленного порога.

Поиск тяжёлых callbacks

Особого внимания требуют

  • OnPlayerUpdate;
  • частые таймеры;
  • обработчики команд;
  • загрузка аккаунта;
  • сохранение всех игроков;
  • обработка динамических зон;
  • массовое создание объектов;
  • обработка игровых событий.

OnPlayerUpdate вызывается очень часто

Не размещайте в нём:

  • полные циклы по всем игрокам;
  • SQL-запросы;
  • чтение файлов;
  • формирование больших строк;
  • пересчёт всей экономики;
  • повторное создание интерфейсов;
  • тяжёлые геометрические проверки без ограничений.

Переносите действия

  • в событие изменения состояния;
  • в более редкий общий таймер;
  • в callback завершения запроса;
  • в кэшируемую функцию;
  • в плагин, если для задачи существует надёжная реализация.

Оптимизация циклов Pawn

Не перебирайте максимальный размер без необходимости

Неэффективный вариант:

for (
 new i = 0;
 i < MAX_SERVER_ITEMS;
 i++
)
{
 if (!ItemData[i][itemExists])
 {
 continue;
 }

 UpdateItem(i);
}

Если из 50 000 слотов используются только 300, большая часть итераций выполняется впустую.

Храните список активных элементов

for (
 new index = 0;
 index < g_ActiveItemCount;
 index++
)
{
 new itemid =
 g_ActiveItems[index];

 UpdateItem(itemid);
}

Выносите неизменяемые значения из цикла

Не вызывайте повторно одну и ту же тяжёлую функцию внутри каждой итерации, если её результат не меняется.

Завершайте поиск после нахождения результата

for (new i = 0; i < count; i++)
{
 if (Items[i] == searchedItem)
 {
 foundIndex = i;
 break;
 }
}

Не создавайте вложенные циклы без оценки

Цикл по 500 игрокам внутри цикла по 10 000 объектов может привести к миллионам проверок за одно выполнение.

Оптимизация циклов по игрокам

Проверяйте только подключённых игроков

for (
 new playerid = 0;
 playerid < MAX_PLAYERS;
 playerid++
)
{
 if (!IsPlayerConnected(playerid))
 {
 continue;
 }

 ProcessConnectedPlayer(playerid);
}

Для частых операций используйте список активных игроков

Итератор или собственный список позволяет не проверять пустые слоты.

Не запускайте один и тот же полный цикл

  • для каждого подключённого игрока;
  • в каждом обновлении позиции;
  • для каждого динамического объекта;
  • несколько раз в одном callback;
  • для простой проверки одного ID.

Разделяйте обработку по времени

Вместо одновременной проверки всех игроков можно обрабатывать часть списка на каждом запуске общего таймера.

Оптимизация серверных таймеров

Типичные проблемы

  • отдельный частый таймер для каждого игрока;
  • таймер продолжает работать после выхода;
  • несколько одинаковых таймеров запускаются повторно;
  • таймер выполняет полный цикл по серверу;
  • интервал установлен в несколько миллисекунд без необходимости;
  • callback таймера выполняется дольше его интервала.

Плохая архитектура

SetTimerEx(
 "UpdatePlayerData",
 100,
 true,
 "i",
 playerid
);

При большом онлайне создаётся множество частых таймеров.

Практичнее использовать общий таймер

SetTimer(
 "ProcessPlayers",
 1000,
 true
);

Распределяйте тяжёлую работу

Например, не сохраняйте всех игроков в одну миллисекунду. Обрабатывайте несколько аккаунтов за цикл.

Храните идентификаторы таймеров

При отключении игрока или удалении объекта завершайте связанные повторяющиеся таймеры.

Оптимизация строк и форматирования

Не формируйте строку без необходимости

Если сообщение не будет отправлено, сначала выполните проверки, а затем вызывайте format.

Используйте подходящий размер буфера

Слишком маленький буфер обрежет строку, а огромный локальный массив внутри часто вызываемой функции увеличит потребление стека.

Не объединяйте строки многократно в цикле

Для большого административного списка лучше использовать постраничный вывод или заранее рассчитанный буфер.

Не форматируйте одинаковый текст для каждого игрока

Если сообщение одинаковое, сформируйте его один раз и затем отправьте получателям.

Не храните большие временные строки глобально без необходимости

Разделяйте постоянные данные и временные буферы.

Оптимизация журналирования

Не записывайте каждое игровое обновление

Лог позиции каждого игрока несколько раз в секунду быстро создаст большой файл и нагрузку на диск.

Логируйте важные события

  • ошибки;
  • авторизацию;
  • административные действия;
  • экономические операции;
  • наказания;
  • сбои сохранения;
  • медленные функции;
  • подозрительные действия.

Используйте уровни журналирования

ERROR
WARNING
INFO
DEBUG
TRACE

На рабочем сервере

Оставляйте необходимые уровни, а подробный DEBUG включайте временно для диагностики.

Настройте ротацию

Старые журналы следует архивировать и удалять по установленному сроку, чтобы они не заполнили диск.

Оптимизация сервера CRMP начинается не с уменьшения графики или постоянных перезапусков, а с поиска конкретного источника нагрузки. Зависания могут вызывать тяжёлые циклы Pawn, слишком частые таймеры, синхронная работа с файлами, медленные MySQL-запросы, несовместимые плагины, большое количество динамических объектов или постепенное накопление неосвобождённых ресурсов.

Правильная оптимизация должна проводиться по измеримым показателям. Сначала фиксируется нормальная работа сервера, затем воспроизводится проблема, измеряются CPU, память, задержки запросов и время выполнения функций. После этого изменяется один компонент и повторяется тест.

В руководстве разобраны оптимизация игрового мода CRMP, серверных скриптов, MySQL-запросов и плагинов, снижение нагрузки на VPS, устранение зависаний, поиск утечек памяти и проверка результата под нагрузкой.

Обслуживание, журналы и резервные копии сервера:

Администрирование сервера CRMP

Настройка плагинов и устранение ошибок загрузки:

Установка и настройка плагинов CRMP

Настройка и диагностика базы данных:

Подключение MySQL к серверу CRMP

Что означает оптимизация сервера CRMP

Оптимизация — это уменьшение времени выполнения операций и потребления ресурсов без нарушения игровой логики.

Основные цели

  • стабильная работа игрового цикла;
  • отсутствие длительных зависаний;
  • предсказуемое потребление памяти;
  • быстрая загрузка аккаунтов;
  • своевременное сохранение данных;
  • снижение нагрузки на CPU;
  • уменьшение количества запросов MySQL;
  • устранение постепенного ухудшения работы;
  • стабильность при увеличении онлайна.

Оптимизация не должна приводить к

  • потере данных;
  • отключению важных проверок;
  • ухудшению синхронизации;
  • исчезновению объектов;
  • редкому сохранению критических операций;
  • ослаблению античита;
  • скрытию ошибок постоянными перезапусками.

Главный принцип: сначала измерить проблему, затем исправить её и повторно измерить результат.

Какие виды задержек встречаются на CRMP

Серверный фриз

Все игроки одновременно замечают остановку команд, транспорта, таймеров и других игровых систем. Обычно причина находится в Pawn-коде, плагине, синхронной операции или перегруженном VPS.

Высокий сетевой пинг

Игроки продолжают двигаться, но действия приходят с задержкой. Причиной может быть маршрут сети, перегруженный канал или слишком частая синхронизация.

Задержка MySQL

Игровой мир работает, но долго открываются аккаунты, дома, бизнесы, инвентарь или административные журналы.

Постепенное замедление

После запуска сервер работает нормально, но через несколько часов или дней увеличиваются память, количество объектов, таймеров или открытых ресурсов.

Локальная проблема игрока

Зависания наблюдаются только у одного пользователя. Причина может находиться в клиентской сборке, интернете, большом количестве объектов в одной зоне или слабом компьютере.

Кратковременные пики

Сервер зависает во время общего сохранения, загрузки организаций, перезапуска систем или выполнения тяжёлой административной команды.

Фиксация исходных показателей

До изменения кода запишите показатели нормально работающего сервера.

Зафиксируйте

  • средний онлайн;
  • максимальный онлайн;
  • загрузку CPU;
  • потребление оперативной памяти;
  • использование swap;
  • размер базы данных;
  • количество запросов в минуту;
  • время входа игрока;
  • время сохранения аккаунта;
  • размер server_log.txt;
  • время работы до появления проблемы.

Пример журнала измерений

Дата: 31.07.2026
Онлайн: 42 игрока
CPU процесса: 38%
Память RSS: 612 МБ
Swap: 0 МБ
Вход аккаунта: 180 мс
Общее сохранение: 1,8 секунды
Ошибки MySQL: отсутствуют
Время работы: 14 часов

Повторите измерения

Проверяйте показатели:

  • сразу после запуска;
  • через один час;
  • при среднем онлайне;
  • при максимальном онлайне;
  • перед зависанием;
  • после исправления.

Создание тестовой среды

Тестовая сборка должна содержать

  • копию игрового мода;
  • копию плагинов;
  • отдельный server.cfg;
  • другой игровой порт;
  • отдельную базу MySQL;
  • тестовые аккаунты;
  • отдельные журналы;
  • закрытый доступ по паролю.

Не подключайте тестовый сервер к рабочей базе

Две сборки могут одновременно изменять одни аккаунты, транспорт и имущество.

Создание копии базы

mysqldump \
--single-transaction \
-u crmp_user \
-p \
crmp_server \
> crmp-test.sql

Импорт в отдельную базу

mysql \
-u crmp_test_user \
-p \
crmp_test \
< crmp-test.sql

Используйте отдельный порт

port 8905
password ТЕСТОВЫЙ_ПАРОЛЬ

Как найти настоящее узкое место

Высокий CPU процесса CRMP

Проверяйте Pawn-циклы, таймеры, callbacks, стриминг и нативные плагины.

Высокий CPU MySQL

Проверяйте медленные запросы, индексы, частые UPDATE и полное сканирование таблиц.

Память процесса постоянно растёт

Проверяйте динамические объекты, таймеры, текстовые элементы, кэш плагинов и версии нативных библиотек.

Высокий I/O диска

Проверяйте журналы, частую запись INI-файлов, дампы, swap и MySQL.

Проблема появляется при входе игроков

Проверяйте загрузку аккаунтов, имущества, динамических объектов и количество последовательных SQL-запросов.

Проблема появляется при общем сохранении

Проверяйте одновременные UPDATE для всех игроков, синхронные операции и слишком большой объём данных.

Диагностика нагрузки на процессор

Просмотр процессов Linux

top

Более удобный монитор

htop

Поиск процесса CRMP

ps aux \
| grep -E "samp|crmp" \
| grep -v grep

Подробные данные процесса

ps -o \
pid,ppid,%cpu,%mem,rss,vsz,etime,cmd \
-p PID

Наблюдение каждую секунду

pidstat \
-p PID \
1

Проверьте

  • постоянную загрузку одного ядра;
  • пики в определённое время;
  • рост нагрузки вместе с онлайном;
  • пик при сохранении;
  • пик при подключении игрока;
  • пик после запуска filterscript;
  • другие процессы, забирающие CPU.

Учитывайте одно ядро

Если процесс использует около 100% одного логического ядра, это уже может быть пределом для основной игровой логики, даже если общий CPU восьмиядерного VPS показывает небольшое значение.

Диагностика оперативной памяти

Общая память VPS

free -h

Память процесса

ps -o \
pid,rss,vsz,%mem,etime,cmd \
-p PID

Карта памяти процесса

pmap -x PID \
| tail -n 20

Следите за RSS

RSS показывает объём физической памяти, который фактически использует процесс.

Записывайте значение периодически

while true
do
 date
 ps -o pid,rss,vsz,%mem,etime \
 -p PID

 sleep 300
done

Признаки возможной утечки

  • память постоянно растёт при одинаковом онлайне;
  • после выхода игроков память не стабилизируется;
  • рост связан с конкретной командой;
  • каждый рестарт filterscript увеличивает память;
  • после нескольких загрузок объектов появляется резкий рост;
  • swap постепенно заполняется.

Проверка нагрузки на диск

Свободное место

df -h

Свободные inode

df -i

Нагрузка диска

iostat -xz 1

Общая активность системы

vmstat 1

Размер каталогов

du -sh \
/home/crmp/server/*

Поиск больших файлов

find /home/crmp \
-type f \
-size +100M \
-print

Источники лишней записи

  • слишком подробный server_log.txt;
  • логирование каждого движения игрока;
  • частое сохранение INI;
  • общий MySQL-журнал;
  • частые резервные дампы;
  • core-файлы после падений;
  • активное использование swap.

Проверка сети и игрового порта

Просмотр UDP-портов

sudo ss -lunp

Сетевой трафик интерфейсов

sar -n DEV 1

Проверка потерь до сервера

ping IP_СЕРВЕРА

Диагностика маршрута

mtr IP_СЕРВЕРА

Отделяйте сетевую проблему от серверной

  • если зависают все игровые системы одновременно — проверяйте сервер;
  • если один игрок имеет высокий пинг — проверяйте его маршрут;
  • если проблема появляется только вечером — проверяйте канал и хостинг;
  • если растёт исходящий трафик — проверяйте интервалы синхронизации;
  • если порт недоступен — проверяйте процесс и firewall.

Измерение времени выполнения Pawn-кода

Для поиска медленных участков можно временно измерять время функций.

Простой пример

new startedAt = GetTickCount();

LoadPlayerInventory(playerid);

new elapsedTime =
 GetTickCount() - startedAt;

if (elapsedTime > 10)
{
 printf(
 "[PERFORMANCE] LoadPlayerInventory: %d ms",
 elapsedTime
 );
}

Измеряйте

  • вход игрока;
  • загрузку персонажа;
  • загрузку транспорта;
  • общее сохранение;
  • обработку команд;
  • создание объектов;
  • работу таймеров;
  • античит-проверки;
  • административные отчёты.

Не оставляйте чрезмерный отладочный вывод

Если измерение выполняется сотни раз в секунду, постоянный printf сам создаст нагрузку. Записывайте только превышение установленного порога.

Поиск тяжёлых callbacks

Особого внимания требуют

  • OnPlayerUpdate;
  • частые таймеры;
  • обработчики команд;
  • загрузка аккаунта;
  • сохранение всех игроков;
  • обработка динамических зон;
  • массовое создание объектов;
  • обработка игровых событий.

OnPlayerUpdate вызывается очень часто

Не размещайте в нём:

  • полные циклы по всем игрокам;
  • SQL-запросы;
  • чтение файлов;
  • формирование больших строк;
  • пересчёт всей экономики;
  • повторное создание интерфейсов;
  • тяжёлые геометрические проверки без ограничений.

Переносите действия

  • в событие изменения состояния;
  • в более редкий общий таймер;
  • в callback завершения запроса;
  • в кэшируемую функцию;
  • в плагин, если для задачи существует надёжная реализация.

Оптимизация циклов Pawn

Не перебирайте максимальный размер без необходимости

Неэффективный вариант:

for (
 new i = 0;
 i < MAX_SERVER_ITEMS;
 i++
)
{
 if (!ItemData[i][itemExists])
 {
 continue;
 }

 UpdateItem(i);
}

Если из 50 000 слотов используются только 300, большая часть итераций выполняется впустую.

Храните список активных элементов

for (
 new index = 0;
 index < g_ActiveItemCount;
 index++
)
{
 new itemid =
 g_ActiveItems[index];

 UpdateItem(itemid);
}

Выносите неизменяемые значения из цикла

Не вызывайте повторно одну и ту же тяжёлую функцию внутри каждой итерации, если её результат не меняется.

Завершайте поиск после нахождения результата

for (new i = 0; i < count; i++)
{
 if (Items[i] == searchedItem)
 {
 foundIndex = i;
 break;
 }
}

Не создавайте вложенные циклы без оценки

Цикл по 500 игрокам внутри цикла по 10 000 объектов может привести к миллионам проверок за одно выполнение.

Оптимизация циклов по игрокам

Проверяйте только подключённых игроков

for (
 new playerid = 0;
 playerid < MAX_PLAYERS;
 playerid++
)
{
 if (!IsPlayerConnected(playerid))
 {
 continue;
 }

 ProcessConnectedPlayer(playerid);
}

Для частых операций используйте список активных игроков

Итератор или собственный список позволяет не проверять пустые слоты.

Не запускайте один и тот же полный цикл

  • для каждого подключённого игрока;
  • в каждом обновлении позиции;
  • для каждого динамического объекта;
  • несколько раз в одном callback;
  • для простой проверки одного ID.

Разделяйте обработку по времени

Вместо одновременной проверки всех игроков можно обрабатывать часть списка на каждом запуске общего таймера.

Оптимизация серверных таймеров

Типичные проблемы

  • отдельный частый таймер для каждого игрока;
  • таймер продолжает работать после выхода;
  • несколько одинаковых таймеров запускаются повторно;
  • таймер выполняет полный цикл по серверу;
  • интервал установлен в несколько миллисекунд без необходимости;
  • callback таймера выполняется дольше его интервала.

Плохая архитектура

SetTimerEx(
 "UpdatePlayerData",
 100,
 true,
 "i",
 playerid
);

При большом онлайне создаётся множество частых таймеров.

Практичнее использовать общий таймер

SetTimer(
 "ProcessPlayers",
 1000,
 true
);

Распределяйте тяжёлую работу

Например, не сохраняйте всех игроков в одну миллисекунду. Обрабатывайте несколько аккаунтов за цикл.

Храните идентификаторы таймеров

При отключении игрока или удалении объекта завершайте связанные повторяющиеся таймеры.

Оптимизация строк и форматирования

Не формируйте строку без необходимости

Если сообщение не будет отправлено, сначала выполните проверки, а затем вызывайте format.

Используйте подходящий размер буфера

Слишком маленький буфер обрежет строку, а огромный локальный массив внутри часто вызываемой функции увеличит потребление стека.

Не объединяйте строки многократно в цикле

Для большого административного списка лучше использовать постраничный вывод или заранее рассчитанный буфер.

Не форматируйте одинаковый текст для каждого игрока

Если сообщение одинаковое, сформируйте его один раз и затем отправьте получателям.

Не храните большие временные строки глобально без необходимости

Разделяйте постоянные данные и временные буферы.

Оптимизация журналирования

Не записывайте каждое игровое обновление

Лог позиции каждого игрока несколько раз в секунду быстро создаст большой файл и нагрузку на диск.

Логируйте важные события

  • ошибки;
  • авторизацию;
  • административные действия;
  • экономические операции;
  • наказания;
  • сбои сохранения;
  • медленные функции;
  • подозрительные действия.

Используйте уровни журналирования

ERROR
WARNING
INFO
DEBUG
TRACE

На рабочем сервере

Оставляйте необходимые уровни, а подробный DEBUG включайте временно для диагностики.

Настройте ротацию

Старые журналы следует архивировать и удалять по установленному сроку, чтобы они не заполнили диск.

Как искать утечки памяти

Под утечкой понимается устойчивый рост памяти из-за ресурсов, которые создаются повторно, но не освобождаются.

Сначала подтвердите рост

  1. Запустите сервер.
  2. Запишите RSS процесса.
  3. Выполните одинаковый набор действий.
  4. Отключите тестовых игроков.
  5. Повторите действия несколько раз.
  6. Сравните память после каждого цикла.

Пример тестового цикла

  • подключить 20 тестовых игроков;
  • авторизовать их;
  • открыть интерфейсы;
  • создать временный транспорт;
  • запустить работу;
  • отключить всех игроков;
  • повторить цикл.

Если память растёт одинаковыми ступенями

Ищите ресурс, который создаётся во время каждого цикла и не уничтожается после его завершения.

Не путайте утечку с кэшем

Кэш может вырасти до определённого предела, а затем стабилизироваться. Утечка обычно продолжает расти при повторении действий.

Накопление ресурсов игрового мода

Даже без классической утечки памяти сервер может постепенно накапливать игровые сущности.

Проверяйте создание и удаление

  • таймеров;
  • динамических объектов;
  • пикапов;
  • зон;
  • текстовых надписей;
  • PlayerTextDraw;
  • временного транспорта;
  • NPC;
  • динамических актёров;
  • кэшированных результатов запросов.

Типичная ошибка

public ShowPlayerInterface(playerid)
{
 CreatePlayerInterface(playerid);
 ShowPlayerInterfaceElements(playerid);

 return 1;
}

При каждом открытии создаётся новый комплект интерфейса.

Практичнее

if (!g_PlayerInterfaceCreated[playerid])
{
 CreatePlayerInterface(playerid);

 g_PlayerInterfaceCreated[playerid] =
 true;
}

ShowPlayerInterfaceElements(playerid);

При отключении игрока

  • уничтожьте его персональные ресурсы;
  • завершите повторяющиеся таймеры;
  • очистите массивы;
  • сбросьте флаги существования;
  • отмените незавершённые операции, если API это поддерживает.

Поиск утечек внутри серверных плагинов

Признаки проблемы плагина

  • рост памяти начался после обновления;
  • рост продолжается при пустом сервере;
  • отключение конкретного filterscript не помогает;
  • проблема исчезает без одного плагина;
  • повторная загрузка системы увеличивает память;
  • появляются ошибки нативных функций.

Порядок проверки

  1. Сохраните рабочую сборку.
  2. Верните предыдущую версию плагина.
  3. Повторите нагрузочный тест.
  4. Отключите необязательные вызовы плагина.
  5. Проверьте официальный список исправлений.
  6. Подготовьте минимальный тестовый мод.

Valgrind используйте только на тестовой среде

valgrind \
--leak-check=full \
--show-leak-kinds=all \
./samp03svr-cr

Valgrind значительно замедляет процесс и не подходит для обычной работы публичного сервера.

Для отчёта разработчику подготовьте

  • версию операционной системы;
  • архитектуру ядра;
  • версию плагина;
  • минимальный пример;
  • последовательность воспроизведения;
  • график роста памяти;
  • журнал ошибок.

Поиск причины полного зависания

Если процесс работает, но сервер не отвечает

Проверьте:

  • загрузку одного ядра;
  • активность диска;
  • swap;
  • соединения MySQL;
  • последние строки журнала;
  • активный общий таймер;
  • недавно выполненную команду;
  • недавно установленный плагин.

Просмотр журнала

tail -n 200 \
server_log.txt

Проверка MySQL

SHOW FULL PROCESSLIST;

Проверка системной нагрузки

top
vmstat 1
iostat -xz 1

Краткая трассировка системных вызовов

sudo strace \
-f \
-tt \
-T \
-p PID

Типичные причины полного фриза

  • бесконечный цикл;
  • слишком большой цикл за один callback;
  • синхронное ожидание внешнего сервиса;
  • зависший нативный плагин;
  • массовое сохранение;
  • блокировка базы;
  • активное использование swap;
  • исчерпание места на диске.

Полезные команды мониторинга Linux

CPU и процессы

top
htop
pidstat -p PID 1

Память

free -h

ps -o \
pid,rss,vsz,%mem,etime,cmd \
-p PID

pmap -x PID

Диск

df -h
df -i
iostat -xz 1
du -sh /home/crmp/server/*

Сеть

sudo ss -lunp
sar -n DEV 1

Служба MySQL

sudo systemctl status mysql

sudo journalctl \
-u mysql \
-n 100 \
--no-pager

Последние ошибки сервера

grep -i \
-E "error|failed|runtime|warning|denied" \
server_log.txt \
| tail -n 100

Не устанавливайте инструменты наугад

Перед использованием на рабочем VPS проверьте назначение команды и создаваемую ею нагрузку.

Нагрузочное тестирование сервера CRMP

Оптимизацию необходимо проверять в условиях, приближенных к реальной работе.

Сценарии теста

  • массовое подключение игроков;
  • одновременная авторизация;
  • загрузка личного транспорта;
  • массовое появление в одной зоне;
  • работа большого количества объектов;
  • общее сохранение;
  • открытие административных логов;
  • перезапуск игровых систем;
  • длительная работа без рестарта.

Во время теста записывайте

  • CPU процесса;
  • CPU MySQL;
  • RSS памяти;
  • использование swap;
  • время SQL-запросов;
  • размер журналов;
  • время выполнения Pawn-функций;
  • задержку команд;
  • ошибки и предупреждения.

Сравнивайте одинаковые условия

Нельзя объективно сравнить две версии, если в одном тесте было 10 игроков, а в другом — 60 и массовое событие.

Проверяйте длительную стабильность

Короткий тест не обнаружит постепенное накопление объектов, таймеров или памяти. Оставляйте тестовую сборку работать несколько часов с повторяющимися сценариями.

Контрольный список оптимизации CRMP

Диагностика

  • зафиксированы исходные показатели;
  • проблема воспроизводится;
  • определён процесс с высокой нагрузкой;
  • проверены CPU, память, диск и сеть;
  • проверены последние журналы;
  • создана тестовая среда.

Pawn-код

  • измерено время тяжёлых функций;
  • нет SQL в частых callbacks;
  • нет ненужных полных циклов;
  • таймеры не дублируются;
  • работа распределена по времени;
  • не создаются повторные интерфейсы;
  • временные ресурсы уничтожаются.

MySQL

  • проверен журнал медленных запросов;
  • тяжёлые запросы проверены через EXPLAIN;
  • созданы необходимые индексы;
  • нет лишнего SELECT *;
  • устранены N+1 запросы;
  • используются асинхронные операции;
  • сохранение не выполняется всем одновременно;
  • связанные операции используют транзакции.

Плагины

  • версии записаны;
  • проверена совместимость;
  • нет ненужных расширений;
  • проверены зависимости;
  • после обновления выполнен тест;
  • сохранены предыдущие рабочие версии.

server.cfg

  • параметры синхронизации не изменены вслепую;
  • измерена нагрузка до и после;
  • проверена отзывчивость;
  • проверен сетевой трафик;
  • проверена работа транспорта и объектов.

Память

  • RSS записывается во времени;
  • повторён одинаковый тестовый цикл;
  • проверено освобождение ресурсов игроков;
  • проверены динамические объекты;
  • проверены таймеры;
  • проверены нативные плагины;
  • рост памяти стабилизируется.

Результат

  • сравнены одинаковые сценарии;
  • нагрузка действительно снизилась;
  • игровая логика не нарушена;
  • данные сохраняются;
  • нет новых ошибок;
  • создана резервная копия рабочей версии.

Частые вопросы по оптимизации сервера CRMP

Почему пустой сервер использует много CPU?

Проверьте частые таймеры, бесконечные циклы, обработку объектов, filterscripts и несовместимые плагины.

Почему нагрузка растёт вместе с онлайном?

Чаще всего увеличивается число циклов по игрокам, запросов MySQL, объектов, интерфейсов и операций синхронизации.

Почему сервер зависает при входе игрока?

Проверьте количество запросов при авторизации, загрузку имущества, создание объектов и выполнение тяжёлых функций в callback подключения.

Почему сервер зависает во время сохранения?

Возможно, все аккаунты одновременно отправляют большое количество UPDATE или выполняется синхронная операция.

Нужно ли сохранять игроков каждую секунду?

Нет. Критические операции сохраняются сразу, остальные данные — периодически и распределённо.

Как найти медленную Pawn-функцию?

Временно измеряйте время через GetTickCount и записывайте вызовы, превысившие заданный порог.

Можно ли выполнять MySQL-запрос в OnPlayerUpdate?

Не следует. Callback вызывается слишком часто. Перенесите запрос в событие изменения данных или редкий таймер.

Что означает N+1 запросов?

Один запрос получает список записей, после чего для каждой записи выполняется дополнительный запрос.

Как найти медленные SQL-запросы?

Включить журнал медленных запросов и проверить найденные команды через EXPLAIN.

Нужно ли добавлять индекс на каждый столбец?

Нет. Индексы создаются под реальные условия поиска, соединения и сортировки.

Почему MySQL не использует созданный индекс?

Причиной может быть порядок столбцов, тип сравнения, функция над столбцом, низкая избирательность или другой более выгодный план.

Асинхронный запрос всегда быстрый?

Нет. Он не блокирует игровую логику, но может оставаться тяжёлым для базы.

Поможет ли увеличение мощности VPS?

Поможет только при реальном недостатке ресурсов. Бесконечный цикл, плохой запрос или утечку необходимо исправлять в коде.

Можно ли уменьшить sleep до нуля?

Экстремальное уменьшение может значительно повысить CPU. Значение нужно проверять на тестовой сборке.

Что произойдёт при уменьшении sync rate?

Обновления станут чаще, но возрастут нагрузка и сетевой трафик.

Почему память увеличилась после запуска и остановилась?

Плагины и кэши могли выделить рабочую память. Это не обязательно утечка, если дальнейшего роста нет.

Как подтвердить утечку памяти?

Повторяйте одинаковые действия и проверяйте, продолжает ли RSS расти после освобождения игровых ресурсов.

Что чаще всего не удаляется?

Таймеры, динамические объекты, TextDraw, временный транспорт, кэш запросов и ресурсы плагинов.

Можно ли запускать Valgrind на рабочем сервере?

Не рекомендуется. Он значительно замедляет процесс и предназначен для отдельной тестовой среды.

Поможет ли автоматический рестарт каждый час?

Он временно сбросит память и нагрузку, но скроет причину проблемы и может привести к потере данных.

Как часто проверять производительность?

После крупных обновлений, изменения плагинов, роста онлайна и появления новых задержек.

Нужно ли оптимизировать код, который выполняется один раз при запуске?

Только если он заметно задерживает старт или потребляет чрезмерные ресурсы. Сначала оптимизируйте часто выполняемые участки.

Как понять, что оптимизация помогла?

Сравните одинаковые тестовые сценарии по CPU, памяти, времени запросов, задержке команд и стабильности длительной работы.

Официальные и технические источники

Заключение

Оптимизация сервера CRMP должна начинаться с измерений. Сначала определите, где возникает нагрузка: в игровом процессе, MySQL, диске, сети или серверном плагине.

В Pawn-коде особого внимания требуют частые callbacks, полные циклы, отдельные таймеры для каждого игрока и повторное создание динамических ресурсов. Тяжёлую работу необходимо распределять по времени и запускать только при реальном изменении данных.

MySQL-запросы следует выполнять асинхронно, но одной асинхронности недостаточно. Проверяйте медленные запросы через журнал и EXPLAIN, добавляйте обоснованные индексы, выбирайте только необходимые поля и устраняйте N+1 операции.

Параметры синхронизации в server.cfg изменяются только после измерений. Частые обновления повышают отзывчивость, но увеличивают нагрузку и сетевой трафик.

При росте памяти повторяйте одинаковый тестовый сценарий и проверяйте освобождение таймеров, объектов, TextDraw, транспорта и ресурсов плагинов. Постоянный рост RSS после каждого цикла указывает на необходимость дальнейшей диагностики.

Не используйте частые перезапуски как основное решение. Они временно скрывают перегрузку или утечку, но не устраняют ошибку и могут приводить к потере последних данных игроков.

После каждого изменения выполняйте нагрузочный тест, сравнивайте показатели с исходной версией и сохраняйте рабочую резервную копию.

Обслуживание и контроль сервера:

Администрирование сервера CRMP

Оптимизация подключения и запросов базы:

Настройка MySQL для CRMP

Диагностика серверных расширений:

Плагины сервера CRMP

Настройка параметров производительности:

Настройка server.cfg для CRMP

RSS инструкций
0 комментариев 0.0 из 0 оценок
MIAMI RP COMMUNITY

Комментарии к инструкции

Обсудите решение, задайте вопрос или дополните инструкцию

Всего: 0
Страница: /
Показано: 0
Добавление комментариев сейчас недоступно для текущего пользователя.