【问题标题】:Cassandra account modeling with indexes带有索引的 Cassandra 帐户建模
【发布时间】:2015-11-17 13:05:52
【问题描述】:

我们在 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.';

这对于电子邮件访问来说很好,因为当我们知道登录后的电子邮件地址时,我们可以快速访问每个帐户。

除了电子邮件登录选项外,用户还可以使用社交帐户登录/注册。当使用社交帐户登录时,流程是转到社交网络,接收社交 ID(facebook、twitter、linkedin),可能还有电子邮件并通过社交 ID 查询帐户表以获取完整帐户,或者只是电子邮件并继续在每个 API 请求上使用电子邮件。

我们目前在facebook_idtwitter_idlinkedin_id 上添加了索引来支持这一点,因为我们处于 MVP 阶段,只有一个节点,我们选择 fats 实现而不是性能。

对此建模的正确方法是什么?以下是我们正在考虑的几个建议:

  • 离开索引实施,因为通过社交 ID 获取仅在登录一次时发生(在使用该电子邮件之后)
  • 每个社交 ID 都有一个表格,用于保存社交 ID 电子邮件对
  • 为每个社交 ID 设置一个表格,用于保存完整帐户(帐户可以编辑,这样会增加更新的复杂性)
  • 还有别的吗?

还有一个问题,当您对很少发生的访问路径进行建模时,具有高基数字段(如社交 ID)的索引实现真的那么糟糕吗?

【问题讨论】:

    标签: cassandra data-modeling datastax-java-driver cassandra-2.1


    【解决方案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表中插入一行,在account_login_source表中插入对应行。

    这样,您的用户可以使用多个登录源并将它们链接到一个帐户。您只需运行 2 个非常有效的查询即可让用户登录。

    在不指定分区键的情况下使用二级索引肯定会成为问题,因为随着集群的增长,请求最终会超时。 如果您运行如下查询:

    SELECT * FROM account_by_email where facebook_id = 'userid';
    

    Cassandra 必须扫描集群中的每个节点,以获得单行。 根据经验,我建议不要使用这种技术,一旦在生产中会导致很多绝望......

    【讨论】:

    • 唯一的问题是我们 90% 的时间都使用电子邮件(我们的访问令牌转换为电子邮件,因此每个 API 都会从中读取以验证用户),因此可能是您优化电子邮件表的建议的一个很好的补充或将电子邮件保留为 PK 而不是用户 ID,因为如果我们没有收到来自社交网络的电子邮件,我们会要求用户提供它,以便我们始终拥有它。
    • 第二个表应该有键 ((user_social_id, login_source)) 因为它不能为单个社交 ID 聚集
    • 确实是第二张表的partition_key是(user_social_id, login_source),打错了。
    • 确实不清楚该电子邮件是否始终存在。如果是这样,它可以替换 uuid 并作为您帐户的唯一 ID。仍然需要第二个表作为倒排索引来查找哪个帐户(电子邮件地址)对应于社交帐户,因为二级索引最终无法足够快地回答。
    • 感谢您的回答和交谈,需要听取更多意见。我也有类似的想法……
    猜你喜欢
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    • 2022-07-01
    • 2014-09-17
    • 2017-08-12
    相关资源
    最近更新 更多