用户数据的No-SQL(Cassandra)数据建模

时间:2018-05-16 22:52:06

标签: cassandra nosql

如何在Cassandra中为用户数据建模?

  1. 用户数据的单个表,按用户ID分区,不同的组件读/写到不同的列?
  2. 具有相同密钥结构的多个表(每个组件一个),偶尔需要在分区键上“连接”在一起?
  3. 我们拥有与客户相关的各种数据和元数据,我们目前将这些数据和元数据保存在具有相同分区的单独表格中。聚类键。

    这会导致来自不同表格(例如分析)的用户信息不足,有效地“加入”其分区键上的两个或更多Cassandra表。

    从积极的方面来说,插入表格是独立完成的。

    同时更新相同分区键但不同列的数据时是否存在竞争条件?或者在SSTables上优雅地合并增量?

    是否有多个表具有相同的分区(和群集)键或反模式?

    为了使这更具体,让我们说:

    CREATE TABLE example (
      pk text PRIMARY KEY
      col_a text
      col_b text
    )
    

    假设对于给定的分区键(pk),最初col_acol_b都有一些值(即非空)。并且两个并发插入更新它们中的每一个。那里有没有竞争条件?丢失了两个更新中的一个,尽管写入了不同的列?

1 个答案:

答案 0 :(得分:1)

摘要

写冲突是您不必担心的事情。所有INSERTS / UPDATES / DELETES都是Cassandra的Upserts。 Cassandra的所有内容都是以列为基础的。

Cassandra使用最后写赢策略来管理冲突。正如您在下面的示例中所看到的,无论何时更改值,都会更新与该列关联的时间戳。由于您正在运行并发更新,并且一个线程将更新 col_a ,另一个线程将更新 col_b

实施例

初始插入

cqlsh:test_keyspace> insert into race_condition_test (pk, col_a, col_b ) VALUES ( '1', 'deckard', 'Blade Runner');
cqlsh:test_keyspace> select * from race_condition_test ;

 pk | col_a   | col_b
----+---------+--------------
  1 | deckard | Blade Runner

(1 rows)

时间戳在初始插入中是相同的

cqlsh:test_keyspace> select pk, col_a, writetime(col_a), col_b, writetime(col_b) from race_condition_test ;

 pk | col_a   | writetime(col_a) | col_b        | writetime(col_b)
----+---------+------------------+--------------+------------------
  1 | Deckard | 1526916970412357 | Blade Runner | 1526916970412357

(1 rows)

一旦 col_b 被提升,它的时间戳会发生变化以反映变化。

cqlsh:test_keyspace> insert into race_condition_test (pk, col_b ) VALUES ( '1', 'Rick');
cqlsh:test_keyspace> select pk, col_a, writetime(col_a), col_b, writetime(col_b) from race_condition_test ;

 pk | col_a   | writetime(col_a) | col_b | writetime(col_b)
----+---------+------------------+-------+------------------
  1 | Deckard | 1526916970412357 |  Rick | 1526917272641682

(1 rows)

col_a 更新后,它的时间戳也更新为新值

cqlsh:test_keyspace> insert into race_condition_test (pk, col_a) VALUES ( '1', 'bounty hunter');
cqlsh:test_keyspace> select pk, col_a, writetime(col_a), col_b, writetime(col_b) from race_condition_test ;

 pk | col_a         | writetime(col_a) | col_b | writetime(col_b)
----+---------------+------------------+-------+------------------
  1 | bounty hunter | 1526917323082217 |  Rick | 1526917272641682

(1 rows)

建议

我的建议是您使用一个表来满足您的查询需求。如果您需要通过 pk 进行查询,请创建一个包含所需列的单个表。这样,您将拥有一个可以有效回读的宽行,作为单个查询的一部分。

您在选项2中描述的数据模型有点关系,并不适合Cassandra。你不能在cassandra中本地执行连接,你应该避免在客户端执行连接。

数据模式规则:

规则1:在整个群集中均匀分布数据  您需要创建一个分区键,以确保数据在整个群集中均匀分布,并且您没有任何热点。

规则2:最小化分区数量  每个分区可能驻留在不同的节点中,因此您应该尝试创建一个场景,为了性能,您的查询理想地只针对一个节点。

规则3:围绕您的查询建模

  1. 确定要支持的查询
  2. 创建一个满足您查询的表(意味着每个查询模式应使用一个表)。
  3. 如果您需要支持更多查询模式,请将数据反规范化为为这些查询提供服务的其他表。避免使用辅助索引和物化视图,因为它们目前不稳定,并且当您开始增加群集时,第一个可能会产生重大性能问题。
  4. 如果您想了解更多关于此信息,请参阅此数据传输页面: Basic Rules of Cassandra Data Modeling