如何在cassandra中保持多个表之间的数据一致性?

时间:2016-12-31 03:17:07

标签: cassandra data-modeling cql data-consistency

我无法确定如何跨多个表维护属性更新,以确保数据的一致性。

例如,假设演员和粉丝之间有多对多的关系。粉丝可以支持很多演员,演员有很多粉丝。我制作了几个表来支持我的查询

CREATE TABLE fans (
    fan_id uuid,
    fan_attr_1 int,
    fan_attr_2 int
    PRIMARY KEY ((fan_id))
)

CREATE TABLE actors (
    actor_id uuid,
    actor_attr_1 int,
    actor_attr_2 int
    PRIMARY KEY ((actor_id))
)

CREATE TABLE actors_by_fan (
    fan_id uuid,
    actor_id uuid,
    actor_attr_1 int,
    actor_attr_2 int
    PRIMARY KEY (fan_id, actor_id)
)

CREATE TABLE fans_by_actor (
    actor_id uuid,
    fan_id uuid,
    fan_attr_1 int,
    fan_attr_2 int
    PRIMARY KEY (actor_id, fan_id)
)

我们说我是粉丝而且我在我的设置页面上,我想将fan_attr_1更改为其他值。

fans表上,我可以更新我的属性,因为应用程序知道我的fan_id并且可以关键。

但是,如果没有首先查询与粉丝绑定的actor_ids,我就无法更改fan_attr_1上的fans_by_actor

如果您要更新fansactors的任何属性,则会出现此问题。

我尝试在网上寻找遇到类似问题的人,但我无法找到它们。例如,在Datastax的数据建模课程中,他们将实例与演员和视频一起用于多对多关系,其中他们有表actors_by_videovideos_by_actor。该课程与我咨询过的其他在线资源一样,在查询后讨论了建模表,但还没有研究如何维护数据完整性。在actors_by_video表中,如果我想更改actor的属性会发生什么?是否必须遍历actors_by_video的每一行才能找到包含actor的分区并更新属性?这听起来非常低效。另一个选择是预先查找视频ID,但我读到其他地方,在写入之前读取的是Cassandra中的反模式。

从数据建模的角度或从CQL的角度来看,解决此问题的最佳方法是什么?

编辑: - 修正句子存根 - 增加了背景和先前的研究

3 个答案:

答案 0 :(得分:0)

  

数据建模

Cassandra不是关系数据库,DataModeling需要遵循一些基本规则,在高层次上,我们的数据模型需要遵循以下目标。

1)在群集周围均匀分布数据

2)最小化读取的分区数

此外,我们应该选择一个大表而不是将其分成多个表并在表之间添加关系。在这种方法中,将发生重复记录。记录重复并不是一个更昂贵的操作,因为它只需要更多的磁盘空间而不是CPU,内存,磁盘IOP或网络。

请注意,列键名称和值存在大小限制。最大列键(和行键)大小为64KB。最大列值大小为2 GB。但是因为没有流,并且在请求时将整个值提取到堆内存中,将大小限制为仅几MB。

更多信息:

http://www.datastax.com/dev/blog/basic-rules-of-cassandra-data-modeling

http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/

http://www.ebaytechblog.com/2012/08/14/cassandra-data-modeling-best-practices-part-2/

https://docs.datastax.com/en/cql/3.1/cql/cql_reference/refLimits.html

  

CQL

可以使用BatchMaterialized Views维护表间的一致性。物化视图可从3.0版本中获得

请参阅

How to ensure data consistency in Cassandra on different tables?

  

我的偏好是更改数据模型并进行设计   因此对于我们的查询,如果可能的话,将它作为一个大表。

希望它有帮助!

答案 1 :(得分:0)

物化视图可能是最佳选择:

CREATE MATERIALIZED VIEW actors_by_fan 
AS SELECT fan_id, actor_id, actor_attr_1, actor_attr_2
FROM fans 
PRIMARY KEY (fan_id, actor_id);

CREATE MATERIALIZED VIEW fans_by_actor
AS SELECT actor_id, fan_id, fan_attr_1, fan_attr_2
FROM actors 
PRIMARY KEY (actor_id, fan_id);

在3.0之前的版本中,创建二级索引并评估其性能是否可接受。稍后,升级到3.x后,只需删除二级索引并创建物化视图。

答案 2 :(得分:0)

解决这些问题的方法是手动更新所有已更改的记录。

由于您无法使用实体化视图,因此要更新数据fan_attr_1,您需要:

  1. 通过发出fan
  2. 更新UPDATE fan ... WHERE fan_id = xxx
  3. 通过actor_id actors_by_fan选择SELECT actor_id ... WHERE fan_id = xxx中的所有fans_by_actor
  4. 通过发出UPDATE fans_by_actor ... WHERE actor_id IN (...)更新actor_id表中的所有相应行,或者循环actor_id并运行每个更新异步。
  5. 只要您在步骤2中有少量BATCH,例如少于20,您就可以对所有查询进行分组,并通过在一个numpy.min中运行它们来保持表之间的强一致性。您需要以其他方式保证表之间的一致性。

    这听起来效率低,但我认为还有其他更智能的解决方案。顺便说一句,您发出一个读取(步骤2)和多个写入(步骤1和步骤3)。这不会成为世界的终点,特别是如果你不经常改变所有的属性(例如,每10毫秒)。