Лаги в игре: причины и способы борьбы

Тема в разделе "Игровые сервера", создана пользователем jesuspunk, 4 авг 2015.

  1. jesuspunk

    jesuspunk Администратор Команда форума

    Лаги в игре: причины и способы борьбы


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

    Вступление


    Итак, лагом в общем случае можно назвать все внутри-компьютерные явления, которые мешают нормальной игре. Примеры: "слайд-шоу", зависание картинки, зависание игровых объектов. Но соседа с перфоратором к лагам отнести нельзя, хотя играть он мешает

    Все причины лагов можно разделить на:
    1)
    Проблемы на компьютере игрока - их в силах решить сам игрок;
    2) Проблемы на канале связи между компьютером игрока и сервером;
    3) Проблемы на сервере.

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

    Список определений


    ХЛ, Half-Life - в статье используется как название движка (но не игры про Гордона Фримена!). Данные из статьи применимы ко всем модам, созданным на этом движке, в том числе и для Counter-Strike.

    Клиент - это программа (Half-Life), запущенная на компьютере игрока, которая обменивается данными с сервером и рисует картинку игрового мира.

    хлдс, HLDS, Half-Life Dedicated Server - это программа такая, собственно серверная часть для Half-Life.
    Сервер - Компьютер, на котором запускается хлдс.

    Квар, он же CVar, он же Console Variable - переменная, использующаяся в Half-Lfe, изменяющая какие-либо параметры игры. Может быть изменена пользователем из консоли (отсюда и название). Квары используются как на клиенте, так и в хлдс. Квары, влияющие только на серверную часть, имеют префикс sv_ (примеры - sv_gravity, sv_clienttrace); Квары, влияющие только на клиент имеют префикс cl_ (cl_lw, cl_lc, cl_updaterate).

    Список кваров


    Список кваров, назначение которых необходимо знать:
    1) Клиентские:
    cl_updaterate
    - количество пакетов в секунду, которое клиент хочет получать от сервера (именно хочет, но не факт что получит), 1/сек
    cl_rate - исходящая полоса пропускание клиента (для данных от клиента к серву), байт/сек,
    то есть максимальная скорость передачи данных к серверу
    rate - входящая полоса пропускания клиента (для данных от сервера к клиенту), байт/сек, или максимальная скорость передачи данных к клиенту
    net_graph - определяет тип отображения статистики по сетевому подключению. может принимать значения от 0 до 3 (об это позже)

    2) Серверные:
    sv_maxrate
    - максимальная скорость отдачи данных для одного клиента, байт/сек
    sv_minrate - минимальная скорость отдачи данных для одного клиента, байт/сек
    sv_maxupdaterate - максимальное количество пакетов в секунду, которое может быть передано одному клиенту.
    sv_minupdaterate - минимальное количество пакетов в секунду, которое может быть передано одному клиенту.
    sys_ticrate - определяет максимальное количество кадров, которые сервер может обсчитать за секунду. В хлдсе используется значение 1000/sys_ticrate (это в миллисекнудах) как интервал перерыва между обсчетом кадров.

    Матчасть. Как хлдс контролирует поток данных к клиентам.


    Отдача данных в хлдс контролируется отдельно для каждого клиента, на основе двух факторов:
    1) количество пакетов в секнуду, передаваемых клиенту, назовем это значение updrate
    2) максимальная скорость передачи к клиенту, назовем это значение cmrate.

    I. Исходными данными для определения updrate служат три переменные - это клиентская cl_updaterate, и серверные sv_maxupdaterate и sv_minupdaterate. Алгоритм определения updrate можно записать так:

    updrate := cl_updaterate;
    if updaterate > sv_maxupdaterate then updaterate = sv_maxupdaterate;
    if updaterate < sv_minupdaterate then updaterate = sv_minupdaterate;


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

    Вот несколько примеров для лучшего понимания:
    cl_updaterate=30, sv_minupdaterate=20, sv_maxupdaterate=60. В Этом случае клиент будет получать от сервера 30 пакетов в секунду, т е что клиент хотел, то и получил.

    cl_updaterate=100, sv_minupdaterate=20, sv_maxupdaterate=60. В Этом случае клиент будет получать от сервера 60 пакетов в секунду, тк значение уперлось в верхний порог.

    cl_updaterate=10, sv_minupdaterate=20, sv_maxupdaterate=60. В Этом случае клиент будет получать от сервера 20 пакетов в секунду, тк значение уперлось в нижний порог.

    II. Исходными данными для cmrate служат значения клиентской переменной rate и серверных sv_maxrate и sv_minrate. Алгоритм определения точно такой же, как и у updrate, то есть по умолчанию cmrate = rate, однако если значения вылазит за пределы sv_minrate или sv_maxrate, то оно ограничивается.

    Матчасть. Как хлдс формирует пакеты. Что такое choke. (Упрощенный вариант)


    При работе хлдс все данные, которые должны быть посланы клиенту, складываются в отдельный буфер (он свой для каждого клиента), где и ждут момента, когда подойдет время их пересылки. Как только время подошло, данные начинаются записываться в пакет. На размер пакета накладывается ограничение по cmrate, чтобы не перегрузить полосу, отведенную клиенту. Максимальный размер пакета, связанный с этим ограничением, может быть вычислен как cmrate/updrate, то есть максимальная скорость делится на количество пакетов в секунду. Но что будет, если данных сервер сгенерировал больше, чем может отправить? Тогда все просто - в пакет записываются только данные, которые укладываются в максимальный лимит, остальные остаются ждать следующей пересылки. Так же в пакет дописывается однобайтовое сообщение svc_choke, которое сигнализирует о том, что хлдс не смог послать все данные, которые сгенерировал. Да, эти данные придут к клиенту в следующем пакете, однако придут они уже с задержкой. А если очередь данных на хлдсе разрастается и никогда не заканчивается, то на клиенте можно наблюдать нехилый такой рост пинга, и значение choke = 99 (его можно посмотреть в net_graph 3).
    Отдельным пунктом стоит отметить то, что проверка на размер пакета осуществляется только если сервер работает в Internet режиме (sv_lan 0). При sv_lan 1 эта проверка отключается. Это может быть причиной появления лагов при переводе хлдса на sv_lan 0 при ненастроенных sv_maxrate/sv_minrate.

    Проводим диагностику.


    Итак, чтобы избавиться от лагов, надо знать их причину. А причину нам поможет узнать очень хорошее встроенное в хл средство под названием net_graph, которе отображает в реальном времени информацию, связанную с передачей данных. Имеется 3 режима отображения, мы будем пользоваться первым (net_graph 1).
    Для начала дадим описание того, что там вообще отображается:
    1285349204_1273729986_netgraph.gif

    1 строчка - фпс, интервал десинхронизации (грубо говоря - пинг), значение cl_updaterate
    2 строчка - информация о данных от сервера: текущий размер пакета и средняя скорость приема
    3 строчка - информация о данных к серверу: текущий размер пакета и средняя скорость отдачи
    4 строчка - график данных от сервера. Каждая точка - входящий пакет, высота точек показывает задержку (пинг), чем выше точка, чем больше задержка. Сами точки могут быть 3-х цветов: зеленые - нормальный пакет, пришел вовремя, нигде не задержался :) желтый - пакет с маркером choke, значит сервер не смог отправить все данные из-за политики рейтов; красный - пакет потерялся на просторах интернета ;). Количество loss (потерянных паетов) и choke пакетов можно так же увидеть в цифрах режиме net_graph 3. Значение, отображаемые там нужно понимать так - сколько пакетов из последних 100 было потеряно(loss) или переполнено(choke).
    5 строчка - текущее значение cl_cmdratre
    6 строчка - два графика (хотя трудно их там разглядеть)Обновляются они синхронно, каждый столбец соответствует одному кадру, который отрисовывает клиент.
    Первый график- высотой в один пиксель в самой нижней части. Содержит красные точки. Ими помечаются кадры, в которые не были отправлены cmd пакеты к серверу (можно сказать, аналог choke для клиента, то есть у клиента есть данные для отправки, но отправить он их не может, так как время отправки еще не подошло). В случае, если пакеты отправляются на сервер после отрисовки каждого кадра, графика вообще не видно.
    Второй график - фиолтеовый в нижней части и красный в верхней - показывает уровень десинхронизации состояния клиента и сервера. Если присмотреться внимательно, то он представляет собой гребенку (типа вот так - //////). Степень десинхронизации зависит от того, когда был получен последний пакет от сервера. Следствия - при только что полученном пакете десинхронизация минимальна, а при большой задержке входящих пакетов - максимальна ( график в таком случае превращается в красную полосу в верхней части)

    Примеры, описания и решения


    Ниже набор из 6-ти скриншотов + описание к ним
    1285349419_netgraphs_e.png

    1. Симптомы - слайд-шоу, низкий фпс. Причины: железу на клиенте пора на помойку, либо что-то еще нехило кушает процессорное время (может антивирус, или наоборот какая-то вирусня).
    Решение: Найти и истребить объект, использующий ЦП, либо бежать в магазин за новым компутером.

    2. Видим красные точечки на зеленом графике - потеря пакетов. Это не лучший скрин для демонстрации, но ничего другого нет к сожалению. Симптомы - рывки игроков во время игры, задержка стрельбы или других действий. Особенно хорошо проявляется, когда теряется несколько пакетов подряд.
    Решение: Единого способа нет, т к причина может быть независящей от вас (может пьяный одмин за кабель запнулся). Что можно сделать - вырубить все, что использует сеть, особенно торренты и закачки. Можно попробовать собрать диагностику ping/traceroute и отправить в саппорт провайдера

    3. А тут у нас фриз на компьютере клиента. Симптомы - внезапомное "замирание" игры на 200-300мсек, после чего нормальное продолжение. На нетграфе сопровождается подскоком зеленого графика "под потолок" (на скрине видно два фриза с небольшим интервалом), при этом на нижнем графике нет никаких отклонений. Причины - в основном связаны с драйверами или железом. Фриз, который можно лицезреть на скрине был вызван "умным" поведением винчестера - после 5-6 секнуд неактивности он паркует блок головок, а при при попытке чтения чего-либо распарковывает их, при этом вся система ненадолго зависает.
    Решения - попробовать поставить "рядом" чистую ОС и посмотреть, будут ли фризы на ней. Если будут - проблема с железом, ищем виновника последовательной заменой комплектующих. Если же полет нормальный - дело было в каком-то шибко умном драйвере. Так же может иметь конфликт железо-железо, либо железо-драйвер. В общем, единый путь решения найти трудно.

    4. Самая часто встречающаяся сейчас проблема - choke, желтизна на графике, который должен быть зеленым ;) Симптомы - рост пинга при большом количестве игроков, либо на картах, где видно одновременно много объектов, задержка стрельбы, может быть видно передвижение других игроков и объектов рывками.
    Причина: Сервер генерирует больше данных, чем может передать.
    Решение: Нужно увеличивать скорость, выделяемую клиенту. Ставим rate побольше (например 300000) и смотрим, что произойдет. Если желтизна исчезла - можете поздравить себя с решением проблемы :) Если нет - пытаемся достучаться админу сервера. Если админом являйтесь вы, то тогда ставим в хлдсе sv_maxrate побольше (100000 например). Можно так же поднять и sv_minrate - это поможет игрокам с дефолтным конфигом (там вроде стоит rate 6000) избежать choke-ов и лагов.


    5. Тут бы наблюдаем явную гребенку на нижнем графике - это означает что клинет получает данные через слишком большие интервалы времени. В игре может выражаться небольшим ростом пинга, небольшим подергиванием объектов, игроков.
    Причины: низкий cl_updaterate или очень маленький sv_maxupdaterate на серверное стороне. Лечится увеличением значений этих переменных. Так же такое поведение может вызываться очень низким серверным ФПС (< 50). Решается разгрузкой процессора на сервере, либо поднятием значения sys_ticrate (если он имеет малое значение, т е < 100). Можно еще поставить плагины для увеличения серверного фпс, только при перегруженном ЦП они не спасут.

    6. Здесь можно лицезреть фриз на серверной стороне - был очень большой перерыв между обработками кадров на сервере. На нетграфе выражается подскоком на нижнего графике десинхронизации, при этом с доставкой пакетов проблем не было (верхний график в норме).
    Причин несколько:
    1) обычно связана с высокой загрузкой диска на сервере, когда хлдс пытается что-либо прочитать - происходит задержка.
    2) может происходить из-за блокирующих запросов в перегруженную субд. Решение - переходим на неблокирующие (threaded) запросы, правда тут без переписывания кода плагинов не обойтись
    3) низкий приоритет, данный хлдсу. Если на сервере нашелся процесс с намного более высоким приоритетом, чем хлдс, при этом он загрузил весь (все) ЦП, то хлдс отправляется курить на это время.

    За такие респектные статьи большое спасибо berq! Взято с ©hlds.us.
     
    Арахнид, PrOxOr, Impossибл и ещё 1-му нравится это.
  2. Zhenyazipt

    Zhenyazipt Новичок

    1? меня 3 раза убили за 5мин. И еще 1 вопрос, а будет ли для детинца открыт доступ к игре без подключения инета?