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

В этой статье я без привязки к коду объясню простым языком и в картинках как можно применять в разработке архитектуры авторитарного сервера для онлайн игр шаблон проектирования Event-driven.

Event-driven - Событийно-ориентированная архитектура

Оригинальное изображение схемы архитектуры

А теперь окунемся в теорию этого шаблона на Википедии в русском и английском варианте убедиться что все сделано правильно:

  1. Генераторы событий (агент, продюсер) - они у нас есть и это игровые события (команды, которые могут отправлять игроки и генерировать NPC - например движение и атака на языках программирования LUA, JavaScript и PHP). На данный момент пренебрегая размером пакета я использую пакеты с командами стиля JSON-RPC.

    Сверимся с Википедией

  2. Механизм обработки событий (подписчик) - Это не обязательно должен быть сервис (приложение которое может быть расположено в т.ч. на другой физической машине). В проекте о котором ведется серия статей не основан на сервисной архитектуре

    Почему?

    Если обратится к Википедии одним из главных принципов сервисной архитектуры является независимость от того на каком языке написан сервисы - они могут вызваться через какой-то общепринятый канал взаимодействия (например HTTP запросы в микро сервисной архитектуре через REST API методы). Этот подход хорошо зарекомендовал себя в WEB разработке, но для ММО игрового сервера может быть в ряде случаем медленным, сложным в реализации и поддержке, но не всегда.

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

    Можно видеть и в данных случаях - это WEB приложения и HTTP обмен. Что же касается главных приложений: WebSocket и Игрового сервера (выполняющий расчеты разных механик и команд игроков) - то они тесно связаны языком программирования который обеспечивает им быстрый обмен данных между собой на скорости 1 600 000 запросов в одну сторону, хотя кроме обмена данными другой жёсткой связи нет (т.к. они работают параллельно в разных протоках как разные процессы со своим кодом и набором библиотек).

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

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

    Если допускаются сервисы на основе модели SOA которые можно масштабировать - есть и те сервисы на основе SOA которые нельзя масштабировать
    Если допускаются сервисы на основе модели SOA которые можно масштабировать - есть и те сервисы на основе SOA которые нельзя масштабировать

    Можно использовать и корутину (как например есть в Unity или файберы в PHP) как работающий асинхронно в текущем процессе обработчик событий, и отдельный процесс работающий на той же машине и отдельный поток (thread)

    В любом случае подразумевается что это процесс работает в бесконечном цикле (в языке PHP можно комбинировать это с тиками и сигналами) или ставится на паузу и ждет поступления команд.

    Такой подход можно реализовать используя сокеты (в т.ч. на базе TCP) или прерывания (в PHP это можно реализовать через библиотеку Event что пришла на замену устаревшей Libevent, EV и наконец Swoole которой я отдаю предпочтения за счет того что у нее есть свои библиотеки для создания сервера, корутины для асинхронного выполнения запросов в БД и записи в фаилы и channel как те о которых я писал в статье про обмен данными между потоками, но для обмена данных между корутинами).

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

    Сверимся с Википедией
    первым делом - обработчик событий
    первым делом - обработчик событий
    может, но не обязательно сделать его как сервис
    может, но не обязательно сделать его как сервис

  3. Канал событий (брокер) - в Википедии явно не указано наличие брокера сообщений и его отсутствие не означает что архитектуру нельзя будет назвать Event-driven, однако в высоко нагруженных системах без брокера ваше приложение будет работать медленно если Механизм обработки событий будет и принимать данные от Генератора событий и эти события выполнять в одном потоке.

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

    • Сокеты (PHP предоставляет для этого довольно обширный функционал)

    • Протокол TCP (в т.ч. и его WebSocket протокол который можно создать в PHP на базе функций по работе с сокетами)

    • Shared Memory (PHP предоставляет лишь базовые инструменты в библиотеке Shmop и отдельными функциями при работе с Семафорами)

    • HTTP

    • Каналы (channel) обмена данными между сопроцессами (корутинами) или потоками (процессами) о которых было написано выше .

    В нашем случае брокером выступает Websocket сервер

  4. Последующее действие, управляемое событиями - как опять же нам сообщает русскоязычная версия Википедии этот пункт не является обязательным (как например не на все события игровой сервер обязан что-то возвращать - например когда стало нельзя пройти в координаты из команды игрока).

    После пакетной обработки игровым сервером текущих событий цикла (я его называю кадром сервера) он возвращает все изменения агентам (игрокам).

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

Буду благодарен за лайк к статье.

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


  1. ArchDemon
    15.06.2023 08:05
    +2

    Я бы рекомендовал посмотреть в сторону gRPC вместо JSON-RPC. Бинарный формат позволит сократить трафик. Тема должна быть актуальна для MMO


    1. webrobot Автор
      15.06.2023 08:05
      -1

      Согласен. Но это это не стоит в приоритете , а json более нагляден