Veliri. Дневник разработки 2
клиент-серверное общение
Приветствую DTF. Я все еще продолжаю делать ММО игру.)
Расскажу как я боролся с оптимизацией сетевого трафика. Я вообще не уверен что я все сделал правильно, это мой опыт и все это относится только к вебсокетам в браузере.
Как это было:
До недавнего времени сетевое общение клиента и сервера было организовано на 2х уровнях:
1) действия завязанные на сервер тик
- сбор изменений за прошедший сервер тик(передвижение объектов, обзор (выдел/не видел), обновление объектов)
формирование объектов сообщения по изменениям
проверка на доступность этого сообщения по каждому клиенту (игрок может не видеть тот участок где происходит событие и ему событие не отправляется)
отправка пачек изменений клиенту в формате json, которая выглядит как то так:
Если таких объектов игрок видит 10 то он получит массив из 10 таких изменений, что логично. Так же он получит в других сообщениях изменения своего обзора, перемещение снарядов которые он видит, изменение объектов(хп, энергия, размер и другие метаданные)
В среднем за 1 сервер тик (64мс) 1 клиент получает 6 сообщений (90 сообщений в секунду) с данными изменения мира которого он видит и размер этих сообщений мог изменится от 10 кбайт/c (кбайт) до 75 кбайт/c в зависимости от экшена творящегося вокруг.
2) Какие то события которые не привязаны жестко к сервер тику т.к. происходят редко или отдаются по запросу, для примера:
- произведение выстрела
- использование снаряжения
- взрыв пули (попадание в коллизию)
- нотификация об уроне/заработанных очках
- обновление состояния боевой группы
- серверный прицел
- происходит событие, формируется сообщение
проходит фильтр по обзору или получателю
- отправляется в произвольном json формате.
Если сложить оба эти варианта то на 1 клиента в бою сервер посылал 200 сообщений в секунду, трафиком до 100 кбайт.
На стороне клиента js ловит эти 200 сообщений, парсит в json и нехитрым образом обрабатывает (пожалуйста не бейте меня >_<).
Почему я решил это переделать
В целом меня все устраивало, в сессионной игре на 16 персонажей клиент чувствовал себя +-уверенно и в основном лагал мой код а не сеть. Но я столкнулся с тем что начиная с пинга 50мс++ до сервера клиент начинал очень сильно тормозить в плане управления (у меня авторитарный сервер без предсказаний на стороне клиента).
Проблема была очевидна т.к. сервер тик составлял 64мс то задержка после ввода составляла (25мс + 1-64мс + 64мс + 25мс) + клиент отставал на 1 тик это еще + 64мс (я не уверен в правильности этих расчетов ¯\_(ツ)_/¯), в мое игре не нужен супер быстрый отклик но это уже слишком.
Я не хотел возится с предсказаниям, просто снизил сервер тик до 32мс и задержка стала приемлемой.
Но это повлекло за собой увеличение трафика, кол-во сообщений и кол-во событий на клиенте в 2 раза (а еще кол-во проверок на сервере, но это совсем другая история) и не лучшим образом сказалось на производительности.
Как сейчас
Немного почитав что люди в интернетах пишут я понял что в браузерных играх сообщения отсылаются в виде массива байта, где первый байт отвечает за тип события, а дальше произвольно.
Я решил не искать готового решения и решил проблему в лоб, это выглядит примерно так:
server (go):
client (js):
Конкретно это сообщение стало весить в 2 раза меньше (64б против 29б). Я выделил самые частые сообщения и переписал их в этот формат, в итоге трафик уменьшился в 4 раза, но кол-во сообщений все еще было большое.
Для уменьшения кол-ва сообщений я решил формировать большой пакет данных который хранит в себе все события которые произошли за время тика и отправлять каждому клиенту всего 1 сообщение состоящие из набора байт в таком формате.
EventID — указывает на команду
- следующие 4 байта указывают размер сообщения определённой группы данных
- на 5 байте начинается полезные для клиента данные
- на 5 байте + размер предыдущей группы данных, начинается следующая группа данных
Группы имеют строгий порядок и даже если сообщений нет то просто будет указана длина полезных данных 0, на клиенте это дело выглядит как то так:
В этот пакет попали все сообщения из 1й группы и самые частые сообщения из второй группы что сократило среднее кол-во сообщений c 400/c до 60/c, что все еще много но уже лучше)
Итог
Трафика в игре стало в 2 раза меньше (без учета изменения сервер тика в 4 раза), а бонусом я получил улучшенную производительность клиента, хотя все это работает только в браузерах на хромиуме
Ну а вообще я решал проблему отклика управления, сейчас более чем играбельно с пингом 50мс (но это не точно).