Привет, Хабр! Представляю вашем вниманию перевод статьи "Why you should run your game servers independently from your chat" Joe Hanson.


Разработчики многопользовательских игр часто сталкиваются с дилеммой:

  • Использовать уже существующие игровые серверы (на которых, непосредственно, работает игра) для обеспечения функциональности чата
  • Использовать отдельные сервера для реализации функциональности чата

В конце – концов, это ведь просто чат, так? Маленькие сообщения передаются от пользователя к пользователю/небольшой группе пользователей, вот и всё. Так почему бы просто не добавить немного функционала на уже работающие серверы? Что может пойти не так?

Хотя на первый взгляд это решение может показаться неплохим, в связи с ним может возникнуть ряд проблем. Ниже мы поговорим о том, почему вам стоит разделять игровые сервера и различные социальные фичи (особенно чат). Это разделение позволит нам улучшить производительность и масштабируемость игры, вместе с тем дав нам возможность с лёгкостью добавлять новые «социальные» фичи» и расширять их функциональность в будущем.Подробнее — под катом.

Микросервисы делают игру более управляемой


Микросервисно-ориентированная архитектура разбивает большое приложение, в нашем случае — игру, на небольшие модульные, изменяемые независимо друг от друга сервисы (службы), взаимодействующие друг с другом через простые общедоступные API. Такой подход обеспечивает лёгкость добавления нового функционала и поддержку уже существующего.

Отделение игровых серверов от функциональности чата делает всю инфраструктуру приложения более управляемой и приближает нас к полностью микросервисно-ориентированной архитектуре. Давайте детальнее посмотрим на внутриигровой чат и его «взаимоотношения» с игровыми серверами, обеспечивающими основную функциональность игры.

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

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

Основное назначение игровых серверов (с которым они хорошо справляются, или, по крайней мере, должны хорошо справляться) состоит в синхронизации и передаче игрокам информации о передвижениях и состоянии игроков в реальном. Технологии, используемые на игровых серверах для достижения этих целей, вряд ли являются лучшим решением для реализации чата. Разделённые компоненты, как уже было отмечено, более удобны в поддержке и независимом масштабировании.

image

Рисунок, приведённый выше, иллюстрирует инфраструктуру игры, в которой чат и игровые серверы существуют отдельно друг от друга.

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

Обеспечение бесшовного игрового опыта и эффективной работы чата


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

Разделение чата и игровой логики обеспечивает наиболее эффективное использование процессорных и сетевых ресурсов. Основная задача игровых серверов состоит в обеспечении «бесшовного» (с минимальным количеством лагов/задержек) игрового опыта для каждого игрока. Таким образом, вычислительные мощности серверов должны быть использованы для достижения максимальной производительности игры.

Допустим, у нас есть игра жанра battle arena – например, LoL или EVE Online. Мы хотим обеспечить возможность одновременной игры нескольких сотен игроков в одном игровом мире. Это — тысячи сообщений, представляющих собой информацию обо всех действиях игроков, пересылаемых через игровые сервера в реальном времени. Добавим сюда ещё и сообщения чата. Вполне возможно, что некоторые игроки будут спамить в чат, чтобы специально замедлить скорость работы игрового сервера (на плечах которого будет лежать как передача информации об игровом мире, так и передача сообщений чата). Конечно, возможно отлавливать таких игроков и, например, блокировать для них чат, но для этого всё равно потребуется выполнять дополнительные вычисления на игровых серверах, съедая, таким образом, часть ресурсов, которые могли бы предназначаться для игры.

Игровой сервер и так нагружен разнообразными расчётами, связанными с физикой, графикой и звуком. Добавление функциональности отправки сообщений — от игрока к игроку/группе/команде, их парсинга и маршрутизации — всё это постепенно усложняет инфраструктуру приложения и приводит к ухудшению общей производительности игры.

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

UDP vs. TCP: Когда нужны оба, а когда достаточно одного?


Перейдём к вопросу о выборе между протоколами UDP и TCP для реализации онлайн игр. Какой же из них лучше выбрать в той или иной ситуации?

Динамичные многопользовательские игры (шутеры, MOBA и т.п.) используют протокол UDP для синхронизации передвижений игроков и обновления состояния игры. UDP идеально подходит для обмена отправки этой информации на очень высокой скорости, но он не гарантирует надёжной доставки сообщений и их поступления в правильном порядке.
Протокол TCP гарантирует доставку сообщений, что делает его идеальным выбором для реализации чата. Можно добиться прекрасной производительности, если сама игра будет использовать протокол UDP, а различные социальные фичи — протокол TCP.

image

В играх, не отличающихся высокой динамикой (таких, как пошаговые стратегии), TCP, благодаря своей высокой надёжности, может оказаться подходящим вариантом для реализации как чата, так и игровой логики. Конечно, при этом никуда не девается необходимость разделения игровых серверов и чат-серверов. Особенно, когда игра становится популярной и в неё начинают одновременно играть тысячи игроков.

Задержка также является элементом, требующим внимания, так как стандарты, определяющие допустимые задержки для функционала самих многопользовательских игр и задержки для социальных фич (вроде чата) различаются. Для многопользовательской игры (включающей синхронизацию состояния игры между игроками и передачу информации об одних игроках другим игрокам) задержка не должна превышать 20 миллисекунд, в то время как для приложений чата допустимая задержка составляет 250 миллисекунд.

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

Расширяемость функционала чата


Поддержка чата как standalone-приложения и выбор для этого стандартного промышленного протокола (например, XMPP или WebSockets) или с помощью удалённой службы (например, PubNub) открывает возможность с лёгкостью добавлять новые социальные фичи.

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

Заключение


Большие и маленькие компании, занимающиеся разработкой игр (включая Pocket Games и EVE Online) постепенно переходят (или уже перешли) на эту архитектуру. Начиная с масштабируемости и высокой производительности и заканчивая свободой внедрения новых технологий (без необходимости запираться внутри одного стека), преимущества очевидны: разделение чата и игровых серверов — путь, которым стоит идти.

Комментарии (6)


  1. Enmity
    14.04.2018 10:09

    К сожалению (говорю как близкий к этому делу человек), вынос чата в отдельный сервер не всегда имеет смысл.

    За пример возьмём ту же л2, на ней проще всего объяснить. В л2 существуют несколько пакетов для работы с чатом, которые отсылаются прямо в персонажа, а не в зону. Т.е, к примеру, если мы используем обычный, не глобальный чат, то получателям в фиксированном радиусе от персонажа сервер отсылает пакеты состоящие из типа чата и текста. Если глобальный, то мы отсылаем всем чарам в онлайне. Если партийный, то очевидно, всем персонажам в группе.

    Вопрос: зачем городить огород и выкидывать чат в микросервис, когда в целом чат можно написать за пару часов, и он не будет нагружать примерно ничего? Опять же, это очень сильно зависит от проекта, архитектуры, онлайна игры, количества общающихся в чате (на дворе не 2004, войсчаты во всех минимально стабильных составах игроков давно присутствуют) и общей специфики чата, но… это какого унылого качества должен быть код, чтоб чат хоть как-то грузил машину (вопрос о масштабируемости)? А насчёт задержки — иногда задержка между сервером и клиентом выше. Та же л2 играбельна даже при пинге в 80мс.

    Борьба с ветряными мельницами, имхо.


    1. Neuyazvimy1
      14.04.2018 13:55

      Микросервисы очень удобно использовать когда напрмер ваша команда не успевает уложится в сроки. Вы просто отдаете на аутсорс микросервис который вам нужен, и не паритесь какая там архитектура, говно код или нет и так далее. Он просто работает, и вы его можете масштабировать как хотите.
      Если команда не сильна в архитектуре крупных проектов, это то что нужно. Потому как поддерживать крупный бэкенд с хрупкой архитектурой сложно.
      Например в MMO играх типа WoW, Lineage, Eve Online там даже авторизация, игровая логика, магазин поделены на микросервисы. Не потому что они слабы в архитектуре, а просто потому что так удобнее. За счет этого они более гибче могут настроить свою инфраструктуру и аренда серверов будет дешевле и билды собираются быстрее.
      Ну и конечно можно писать микросервисы на разных языках и фреймворках, а это дает крутую производительность.
      Я например готовые микросервисы с гитхаба использую и это круто экономит время и деньги.
      А вообще мы последний год не пишем свои сервера, пишем только игры и бэкенд логику. За бэкенд отвечают платформы типа GameSparks, Photon и т д. (Ну это конечно зависит от наших целей).


      1. Enmity
        14.04.2018 15:53

        Если брать ретейл L2, то мы получим поделенные на сервисы логинсервер, геймсервер, нпцсервер, CacheD, являющийся прослойкой между базой и гсом и сервер коммуникаций (alt+b, community board, темы, клановые борды, етс. что-то вроде внутриигрового форума, который является практически рудиментом, так как им никто не пользуется.). Чат засунут в l2server, т.е в геймсервер.
        Если брать эмули, то проект поделен на геймсервер и логинсервер в 99% случаев. Смысла в распиливании на микры нет никакого.

        Логика работы чата в л2 объяснена выше. Сервер ловит пакет от клиента, и в виде респонса на этот пакет рассылает, в зависимости от типа чата, получателям сообщения. Чтоб не быть голословным:

        скрин с идеи
        image.


  1. ElectroGuard
    14.04.2018 11:51

    Мода — страшная штука. Особенно в программировании.


  1. VitaZheltyakov
    14.04.2018 13:25
    +1

    Замечания по теме:

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

    — Во-вторых, какая к черту «для приложений чата допустимая задержка составляет 250 миллисекунд» и использование протокола TCP? Это подход программиста-идеалиста, ничего не знающего кроме С++.
    Просто берем HTTP с допустимой задержкой 3 секунды и у вас чат на несколько тысяч человек сможет крутиться на виртуальном хостинге за 20 рублей в месяц.


    1. Enmity
      14.04.2018 16:00

      Замечание к первому замечанию — хорошо работает только если чат между игровыми серверами общий (мы же не о физических машинах говорим, верно?). Во всех иных случаях, имхо, смысла не имеет.