Pull to refresh
21
0
Иван Фатеев @PoisonousJohn

Game Developer, Software Engineer

Send message

В известных мне ECS такого из коробки нет и делается обычно по-разному. Но обычно это выглядит так же как и в реляционной базе данных.

Вводят id для сущностей.

Есть условный ParentEntityIdComponent, который вешается на дочерние сущности. И есть система, которая следит, что в случае, если сущность c ParentId не резолвится, то удаляет текущую сущность.

Так можно сделать иерархию любой сложности.

Можно развернуть и в обратную сторону, что при удалении Parent'a он спрашивает все сущности, которые референсят его id

В итоге, мы получаем каскадное удаление как в базах данных

Лично мне -- было интересно читать, хоть мы и используем другой фреймворк ECS. Было полезно посмотреть как другие организуют свою работу, интересно было провести аналогии.

Ну и тут вопрос скорее не в пропускной способности, а в количестве данных, которые накапливаются. Как видно из расчетов, прирастает примерно по 600Гб в месяц. Бывает нужно делать очень кастомные запросы за довольно большой промежуток времени.
Звучит неплохо. Есть несколько вопросов:

* Приходилось ли ELK стэком визуализировать real-time данные (ну или в случае с Kibana с частым auto-refresh)?
* Какой максимальный объем данных приходилось хранить?
* Какова производительность запросов, например за сколько можно произвести аггрегацию данных всей базы?
* Хватало ли инструментов по визуализации?
Я тут пересчитал все без HDInsight, так как нет смысла это все пихать на Hadoop для таких объемов данных. Apache стэк так же вышел очень рентабельный =)
Google BigQuery тоже клевое решение! На нем можно построить примерно то же самое.
Слишком сложно и дорого.

А в чем сложность? Все сводится к тому, чтобы поднять через портал пару сервисов, и связать их вместе. Ну в нашем случае еще пару Azure Functions написать — но это опциональный шаг, если нужна гибкость.

Такой поток метрик — довольно детская нагрузка. Среди основных требований — легко масштабироваться. Если игра схватит фичеринг, то легко можно вырасти в 10,20,30 раз.

У меня нет большого опыта с ELK. Но те студии, с которыми мы работали, у которых была своя система аналитики, ELK для игровой аналитики не пользовали. Пользовали для мониторинга.
Я писал
Решение «на голых VM» оценивалось ровно с такой же конфигурацией, что предлагает HDInight. Конечно, пожертвовав надежностью, можно уменьшить размер кластера и снизить цену, но это не совсем корректное сравнение.

Дело в том, что цена кластера — важный параметр. Но такой же важный параметр и надежность. Что будет, если эта единственная нода упадет? А что если в аналитику идут бизнес-критичные данные, по которым потом рассматривают тикеты пользователей?

Оценка Apache Stack'a была довольно грубой, широкими мазками, так сказать. Я понимал что конфигурация кластера мощнее, что можно это все развернуть руками на виртуалках меньших размеров, но я так же понимал, что студиям придется заниматься администрированием. А как я и говорил раньше, они не очень готовы в это вкладываться.
Спасибо за отзыв! Со многими пунктами согласен. Видимо не удалось передать основную идею запросов от партнеров. Как я и писал 1к в сек — смешная цифра. Но это то, с чего обычно начинают игры на старте. И заканчивают на этапе сансета.

азур стека пересчитать под более близкую нагрузку к kafka+spark (за $1181) разница будет в тысячи долларов.


Давайте пересчитаем =) Какую нагрузку вы считаете оптимальной для такой конфигурации кластера?

а тысячу событий просто же в mysql/postgres легко писать можно.

Можно, но у нас есть конкретные примеры, когда игровым студиям было проблематично поддерживать БД больших размеров (3TB+), и запросы на них выполнялись многими часами.

плюс возможности kafka+spark+настоящий map-reduce явно другая вселенная в плане возможностей напрограммировать.

Можете рассказать поподробнее, в чем вы видите ограничения по возможностям напрограммировать?

3 ноды по 4 ядра хадупа явно на два-три порядка более, чем 1к событий/сек прожуют

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

Согласен, но задача была посчитать **минимальную** конфигурацию, начиная от 1к событий в сек. Я ориентировался на минимальную архитектуру Apache Stack'a в рамках HDInsight.

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

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

Они хотят начать с малого, платить за то что используют. Но при этом, в случае если игра бомбанет, быть уверенными, что ничего не шлепнется. Быть способными переварить весь возросший объем данных.
Ну это же облако. Там есть свои лимиты на Data Lake Storage аккаунт, но там скорее в деньги упрешься.

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

Команды можно сделать struct, но тогда придется пожертвовать, например, строгой типизацией. Ведь чтобы хранить контейнер полиморфных команд, их все равно придется боксить. Поэтому команду придется привести к одному классу, а тип внутри команды обозначить enum. Параметры же придется организовать в виде какого-нибудь Dictionary<string, object>.

В таком случае команда будет выглядеть примерно так:

public struct Command
{
    public enum Type {
        AddCoins
    }

    public Type type;
    public Dictionary<string, object> parameters;
}

...

void HandleCommand(Command cmd)
{
    switch (cmd.type)
    {
        case AddCoins:
            ...
            break;
    }
}


Если же хранить команды в контейнере не надо, то можно писать отдельные типы команды, а сам тип определять по cmd.GetTypeCode() (обычный GetType боксит), по нему же выбирать какой хэндлер вызвать.
Ну я за эти годы повидал несколько крупных проектов. И там стейт был далеко не маленьким. Например, были прецеденты, когда все получаемые в игре вещи/апгрейды складывались в стейт. Таким образом, если юзер хайлевел, и ему некуда их утилизировать, то они накапливались.

Хоть они и стакались, количество уникальных вещей со временем все равно росло сильно. В итоге стейт очень разрастался.

Это проблема и архитектуры и дизайна, но от этого никто не застрахован.
Адекватным подходом — никак. Либо искать реализации каких-либо древовидных структур, которые скрывают возможность изменения стейта за методами, возвращающими новую ссылку на стейт, а под капотом по-умному генерируют дифф над предыдущим состоянием.
Реактивное программирование не обязательно должно быть полностью по ФП.

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

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

Что касается того, что каждый раз нужно создавать новый стейт — лишние аллокации в играх ни к чему хорошему обычно не приводят :), а если стейт жирный, то можно на хорошие такие грабли наступить.
Я пришел в итоге к выводу, что если такие люди есть, и они не понимают объяснений, что так делать не надо, то с ними лучше не работать. По моему опыту большинство людей достаточно умны, чтобы так не делать. Ну а новичкам всегда код-ревью делать.

Так же чудаки всегда умудрятся любую защиту сломать =)

Если же это действительно критично, и если уж совсем по кананам, то это фиксится просто:

1. Делаем IReadonlyGameState
    public interface IReadonlyGameState
    {
        int coins { get; }
    }
    [System.Serializable]
    public class GameState : IReadonlyGameState
    {
        public int coins { get; set; }
    }

2. В stateUpdated кидается IReadonlyGameState.

У этого подхода есть большой минус.
Если GameState содержит вложенные объекты, то их тоже нужно делать с двумя интерфейсами мутабельным и иммутабельным. Это выливается в кучу проблем.

Если бы C# поддерживал что-нибудь типа const в С++, то ситуация была бы намного проще =)
А можешь поделиться линком где можно поподробнее почитать?
Нет, такой подход не пробовал, но идея интересная :) Не знаю насколько это будет удобно.
Я использовал UniRx для построения запросов к модели. Было довольно удобно.
Это же tutorial, как построить что-то похожее своими руками. Как комбинировать паттерны. Я не претендую на инновационность

Пожалуй перефразирую, чтобы не было дальнейших казусов. =) Спасибо за отзыв.

На счет устоявшейся практики — это преувеличено. Многие пишут код прямо во View и не парятся.
S3 отлично позволяет хранить данные, но не даёт возможности выполнять эффективные поисковые запросы


а возможностей Amazon Athena недостаточно?

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity