База данных Firebase Realtime - поиск совпадений с использованием транзакций = высокая загрузка - PullRequest
0 голосов
/ 21 апреля 2020

Проблема

Я использую базу данных Firebase Realtime (для Unity), чтобы управлять серверной стороной для пошаговой игры, но у меня проблема с сватовством ... высокая загрузка при загрузке.

Каждая онлайн-игра имеет 2 базовых состояния, чтобы избежать участия в игре более 2 игроков: Создано и Зарегистрировано

  • Создано : Игрок пытается присоединиться к игре, если не может найти новую, то будет создана новая игра
  • Регистрация : игрок пытается присоединиться к игре, если найти одну из них изменить состояние от Создано до Присоединено

Я использую RunTransaction, чтобы не допустить присоединения более 2 игроков к игре, но я проверил, что последние данные не были получены из базы данных из-за локальный кэш , добавление keepSynced к моему matches-{lang} дочернему узлу всегда будет содержать самые последние данные, но, естественно, это приводит к высокой загрузке.

private DatabaseReference DatabaseReference()
{
    return FirebaseDatabase.DefaultInstance.RootReference.Child(MatchesLocation(LanguageManager.Manager.GetPlayerLanguageCode()));
}

private DatabaseReference DatabaseReferenceLangMatch(Language language)
{
    return FirebaseDatabase.DefaultInstance.RootReference.Child(MatchesLocation(LanguageManager.Manager.GetLanguageCode(language)));
}

public void ManageKeepSyncedMatches(Language lang)
{
    DatabaseReferenceLangMatch(Language.English).KeepSynced(lang == Language.English);
}

public void JoinMatchTransaction(GameMatchOnline gameMatchOnline, UnityAction<string, bool> callback)
{
    JoinTransactionAbort joinResult = JoinTransactionAbort.None;

    DatabaseReference matchesListRef = DatabaseReference();
    Dictionary<string, object> joinerDict = gameMatchOnline.ToJoinDictionary();

    matchesListRef.Child(gameMatchOnline.matchId).RunTransaction(matchData =>
    {
        Dictionary<string, object> matchDict = matchData.Value as Dictionary<string, object>;
        if (matchDict == null)
        {
            joinResult = JoinTransactionAbort.Null;
            return TransactionResult.Success(null);
        }

        if (!matchDict.ContainsKey("state"))
        {
            joinResult = JoinTransactionAbort.Error;
            return TransactionResult.Abort();
        }
        GameMatchOnline.State state = (GameMatchOnline.State)System.Convert.ToInt32(matchDict["state"]);

        if (state != GameMatchOnline.State.Created)
        {
            joinResult = JoinTransactionAbort.Error;
            return TransactionResult.Abort();
        }

        joinResult = JoinTransactionAbort.None;

        matchDict.Add("joinerInfo", joinerDict["joinerInfo"]);
        matchDict["state"] = joinerDict["state"];
        matchData.Value = matchDict;

        return TransactionResult.Success(matchData);

    }).ContinueWith(task =>
    {
        // Fail
        if (task.IsFaulted || task.IsCanceled)
        {
            UnityThread.executeInUpdate(() =>
            {
                if (joinResult == JoinTransactionAbort.Error)
                {
                    callback(null, false);
                }
            });
        }
        // Can Join match
        else if (task.IsCompleted)
        {
            UnityThread.executeInUpdate(() =>
            {
                if (joinResult == JoinTransactionAbort.None)
                {
                    AddListenerResultsValueChanged(gameMatchOnline.matchId, gameMatchOnline.joinerInfo.userId, gameMatchOnline.isPrivate, gameMatchOnline.language);
                    callback(gameMatchOnline.matchId, true);
                }
                else
                {
                    callback(null, false);
                }
            });
        }
    });
}

Вопрос

  • Удаление keepSynced игроков будет иметь локально кэшированную информацию для matches-{lang}, могу ли я верить, что при этом в игре будет не более 2 игроков? * Транзакции, как предполагается, позволяют избежать подобных проблем.
  • Есть ли способ избежать локального кэша для запроса и, таким образом, всегда получать обновленные данные?
  • Может ли лучшее решение - переместить игры на другой узел, чтобы уменьшить размер узла matches-{lang}?

Спасибо!

1 Ответ

1 голос
/ 21 апреля 2020

Удаление игроков «keepSynced» будет локально кэшировать информацию для «матчей». Могу ли я поверить, что при этом в игре будет не более 2 игроков? * Транзакции, как предполагается, позволяют избежать подобных проблем.

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

Есть ли способ избежать локального кэша для запрос и, следовательно, всегда получать обновленные данные?

Исправление

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

старый ответ:

You _can_ just say `GetValueAsync`, which has to bypass the cache since it will only fire once. You really should use ValueChanged listeners to listen for changes and Transactions to change data if you can to keep everything up to date and to avoid data races.

Может ли лучшее решение быть переместить игры на другой узел, чтобы уменьшить размер узла «спичек»?

Как правило, чем меньше людей обращаются к общему ресурсу, тем выше ваша производительность. Если вы еще этого не сделали, посмотрите сообщение Loteria , чтобы узнать, как команда создала игру в реальном времени на базе данных реального времени, которая была достаточно устойчивой, чтобы быть Google Doodle.

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

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

Надеюсь, что все поможет!

- Патрик

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...