Моделирование аккаунта Cassandra с индексами

Мы моделируем таблицу учетных записей в cassandra с социальными логинами, мы выбрали электронную почту в качестве первичного ключа и реализацию узкой строки. Наша кассандра стоит на версии 2.1.6. Вот определение таблицы:

CREATE TABLE account_by_email (
    email_address text,
    account_password text,
    first_name text,
    last_name text,
    registered_at timestamp,
    roles set<text>,
    facebook_id text,
    twitter_id text,
    linkedin_id text,
    password_reset_token blob,
    password_reset_token_valid_until timestamp,
    profile_image_url text,
    PRIMARY KEY (email_address) ) WITH COMMENT='Accounts in system by email.';

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

Пользователь имеет, помимо возможности входа по электронной почте, возможность входа / регистрации с учетными записями в социальных сетях. Когда используется вход в социальную учетную запись, поток переходит в социальную сеть, получает социальный идентификатор (facebook, twitter, linkedin) и, возможно, электронную почту и запрашивает таблицу учетной записи по социальному идентификатору, чтобы получить полную учетную запись или просто электронную почту и продолжать использовать электронную почту для каждого запроса API.

В настоящее время мы добавили индексы на facebook_id, twitter_id, linkedin_id, чтобы поддержать это, поскольку мы находимся в фазе MVP с одним узлом, и мы предпочли реализацию жира производительности.

Каков правильный способ смоделировать это? Вот пара предложений, о которых мы думаем:

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

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


person Nenad Bozic    schedule 24.08.2015    source источник


Ответы (1)


Мой взгляд на это будет следующим:

Создайте таблицу учетных записей, которая содержит всю информацию о пользователе и использует uuid в качестве ключа раздела:

CREATE TABLE account (
    userid uuid,
    first_name text,
    last_name text,
    registered_at timestamp,
    roles set<text>,
    password_reset_token blob,
    password_reset_token_valid_until timestamp,
    profile_image_url text,
    PRIMARY KEY (userid) );

Создайте единую таблицу, которая связывает любой ваш источник входа в систему с учетной записью пользователя:

CREATE TABLE account_by_login_source (
        user_external_id text, // Can be an email address or a social network id       
        login_source text,   // Can be any of "email", "facebook", "twitter",... 
        userid uuid,
        account_password text,  // only useful for email login, since you handle auth
        PRIMARY KEY ((user_social_id, login_source)));

Когда вы создаете своего пользователя, сгенерируйте uuid, вставьте строку в таблицу учетных записей и соответствующую строку в таблицу account_login_source.

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

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

SELECT * FROM account_by_email where facebook_id = 'userid';

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

person Alexander DEJANOVSKI    schedule 24.08.2015
comment
Единственное, что мы используем электронную почту в 90% случаев (наш токен доступа преобразуется в электронную почту, поэтому каждый API будет читать ее для проверки пользователя), поэтому может быть хорошим дополнением к вашему предложению по оптимизации таблицы электронной почты или оставить электронную почту как PK вместо идентификатора пользователя. так как из социальных сетей, если мы его не получаем, мы просим пользователя предоставить его, чтобы он у нас всегда был. - person Nenad Bozic; 24.08.2015
comment
И вторая таблица, вероятно, должна иметь ключ ((user_social_id, login_source)), так как она не может быть кластеризована для одного социального идентификатора. - person Nenad Bozic; 24.08.2015
comment
Действительно, partition_key второй таблицы (user_social_id, login_source), это опечатка. - person Alexander DEJANOVSKI; 24.08.2015
comment
Было неясно, действительно ли электронная почта присутствовала всегда. Если это так, он может заменить uuid и служить уникальным идентификатором для ваших учетных записей. Вторая таблица по-прежнему нужна в качестве инвертированного индекса, чтобы найти, какая учетная запись (адрес электронной почты) соответствует социальной учетной записи, поскольку вторичные индексы в конечном итоге не будут отвечать достаточно быстро. - person Alexander DEJANOVSKI; 24.08.2015
comment
Спасибо за ответ и разговор, нужно было услышать еще одно мнение. У меня была похожая цепочка мыслей... - person Nenad Bozic; 26.08.2015