使用Cassandra进行一致二级密钥的数据建模

时间:2014-11-28 09:22:16

标签: cassandra data-modeling cql cassandra-2.0

使用Cassandra,

我想用唯一的uuid表示所有用户对象,但也包含一组零个或多个辅助用户密钥以映射到用户。每个辅助键应映射到一个且仅一个用户(id)。因为我需要能够快速查找secondarykey来查找用户,所以我维护了一个单独的查找表,而不是辅助INDEX

我已经建模了这样的数据,但我愿意接受其他选择:

CREATE TABLE users (
    userid uuid PRIMARY KEY,
    name text,
    secondarykeys set<text>
);
CREATE TABLE user_secondarykeys (
    secondarykey text,
    userid uuid,
    PRIMARY KEY(secondarykey)
);

典型的用例是:

我使用辅助密钥mail:andreas@example.org获得此用户,我想看看是否存在具有该辅助密钥的任何用户,如果它不存在,我想创建一个新的用户对象。

我可以查找二级密钥:

SELECT * FROM "user_secondarykeys" WHERE secondarykey = "mail:andreas@example.org";

如果我找不到任何匹配项,我可以插入一个新用户:

BEGIN BATCH
    INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas@example.org'});
    INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0);
APPLY BATCH;

我的问题是,这可能导致数据不一致,因为在我的select和插入之间可以同时插入用户的二级密钥。

我认为如果我可以使我的INSERT事务失败,如果辅助密钥已经存在于user_secondarykeys中,那就行了,因为它还应该将插入恢复到users表中,因为它的原子属性交易。但是,如果存在辅助密钥,我不知道有什么方法可以使INSERT失败。如果我将IF NOT EXISTS添加到第二个插入内容,它将不会还原trasaction,只会避免插入user_secondarykeys,但它仍会插入users

对于如何以可靠的方式实现此用例的任何建议表示赞赏。感谢。

1 个答案:

答案 0 :(得分:0)

起初,我认为您的模型非常复杂,我不确定我是否正确理解您的所有要求。

因此,如果你首先获得这个二级密钥,然后你必须决定做什么 - 添加用户与否 - 那么以下内容对您有用:

不是使用SELECT语句检查user_secondarykeys表是否出现特定的二级密钥,而是使用以下命令:

INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;

因此,如果它适用,则意味着此辅助密钥未与任何用户连接 - 因此有两种情况:用户不存在或用户存在且有人想要添加新的辅助密钥他。以下两种情况都可以完成这项工作:

INSERT INTO users(userid, name, secondarykeys) VALUES(77059e45-5fac-460b-9c4f-47528c292be0, 'Andreas', secondarykeys = secondarykeys + 'mail:andreas@example.org')

因为Cassandra中的插入/更新是幂等的(除了计数器),即使在用户表中已经存在具有该id的用户,这也将起作用 - 这应该只为他添加另一个辅助密钥。

此解决方案的优点在于您将及时消除此差距,这可能会使您“不一致”。您可以保证没有人会使用相同的二级密钥插入两个用户。您指定用户根本没有辅助密钥 - 在这种情况下,您可以直接将他添加到用户表。

  

我认为如果我可以使我的INSERT事务失败,如果辅助密钥已经存在于user_secondarykeys中,那就行了,因为它还应该将插入恢复到users表中,因为它的原子属性交易。但是,如果存在辅助密钥,我不知道有什么方法可以使INSERT失败。如果我将IF NOT EXISTS添加到第二个插入,它将不会恢复trasaction,它将避免插入user_secondarykeys,但它仍将插入用户。

从Cassandra 2.0.6开始,您可以在批处理中使用条件语句,如果不满足任何条件,则该批处理中的所有指令都不会触发。这听起来不错但有一个限制 - 批处理中的所有语句都必须在单个相同的分区上运行。据此,不可能进行跨分区/表条件插入/更新/删除。所以在你的情况下:

BEGIN BATCH
    INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas@example.org'});
    INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;
APPLY BATCH;

甚至不会通过查询验证,因为您尝试在此处操作两个不同的表。

我不确定这是否适合您的其他要求,我需要有关您的查询和数据速度/数量的更多信息。当然,还有其他方法可以对此进行建模。

如果每个用户必须至少拥有一个指定的辅助密钥(例如,电子邮件对于您的用户表来说是一个很棒的唯一密钥),那么这将大大简化问题,但这是您的要求,所以除非您无法改变它们,没有讨论。

希望这会对你有所帮助。 祝你好运!