【问题标题】:cassandra data modelling approach for heavy read/write用于重读/写的 cassandra 数据建模方法
【发布时间】:2019-09-22 03:39:11
【问题描述】:

我是 cassandra 的新手,在以下场景的数据建模方面需要帮助。 在 oracle 中,我有两个类似于下面的表,我正在考虑迁移到 cassandra。

要解决的用例: 1. 繁重的读写。 2. 用户数据是先创建的,我们可以继续添加或删除帐户。 3.还将对其中一个用户帐户进行部分更新,例如更新帐户的金额或某些详细信息。 4. User_data 有一个字段来存储存在的活动 user_accounts 的计数。因此,每当我们在 user_account 表中添加或删除条目/行时。它将触发 user_data 中的更新。

基本上我不清楚如何为这些场景建模。是否只有一个表。但是有了这个,我不确定账户的数量 如果我有一个表并且将 user_accounts 作为 json 类型的列之一。然后,我相信我不能在那个 json 中进行部分更新。

考虑两个表的主要问题是事务管理。 如果我能够添加到 user_account,但无法更新 user_data,那么它将失败。

创建表 USER_DATA ( userId uuid 主键, 名称 varchar, noOfAccounts 整数,

..... #还有一些列...,

);

创建表 USER_ACCOUNTS ( 用户标识 uuid accountId uuid ,
整数, ..... #还有一些列...,

主键 (uuid,accountId) );

我尝试使用 FROZEN USER_ACCOUNTS 列表,但我们需要读取整个列表并在每次添加/删除或更新其中一个条目时回写。

我尝试使用json类型,但没有用。

【问题讨论】:

  • Cassandra 通常由查询用例建模。所有适当建模的身份在查询期间都使用分区键。所以你需要确保你构建的表有一个被查询的分区键。如果您以多种方式查询表(有时在 COLX 上进行过滤,有时使用 COLY),您将设计两张表,一张以 COLX 作为分区键,另一张以 COLY 作为分区键。从关系的角度来看,它并不漂亮,但这就是你实现速度的方式。分区键还决定数据分布。正如您所说,我相信必须完全更新 json 字段。

标签: cassandra


【解决方案1】:

在继续之前让我强调重点:您确定需要 NoSQL 和精确的 Cassandra 来存储用户和帐户吗?

Cassandra 专为大规模分布式数据而设计,并针对非常快速的写入进行了优化。如果您仍在考虑选择解决方案,我建议您花一些时间来调查现有解决方案,以及它们有效/无效的案例。网上有很多文章。例如。 https://www.infoworld.com/article/3268871/how-to-choose-the-right-type-of-database-for-your-enterprise.html

卡桑德拉。

选择结构前的重要问题:

  • 用户添加新帐户和删除帐户的频率如何?
  • 有多少用户同时进行该操作?
  • 一般用户有多少个帐户?

强烈建议为您的所有用例编写性能测试,并在做出任何决定之前检查性能。

原始存储结构可以开始使用性能测试,但改进很少:

create table users.user_data (user_id uuid PRIMARY KEY, 
              name varchar, 
              account_count counter, 
              some_other_column varchar);

create table users.user_account (user_id uuid account_id uuid , amt int, 
PRIMARY KEY (user_id, account_id));
  • users.user_data.account_count 字段的类型为counter
  • 两者 表存储在keyspace 用户中。键空间配置对性能很重要。

如果我们为用户添加新帐户或删除现有帐户,我们应该进行影响多个表的事务。

也许最明显的事情是多分区批次,但那是。仔细阅读:Doc

建议尝试使用驱动程序代码进行异步写入。为您的编程语言选择 Cassandra DataStax 驱动程序。这是一个基于Java 代码的抽象示例来理解这个想法:

session.executeAsync("insert into users.user_account ...");
Futures.addCallback(future,
    new FutureCallback<ResultSet>() {
        @Override public void onSuccess(ResultSet result) {
            // Run query for incrementing counter in users.user_data table
        }
        @Override public void onFailure(Throwable t) {}
    },
    MoreExecutors.sameThreadExecutor() );

更新(2019 年 5 月 14 日):

替代解决方案:单表和静态列看看https://blog.ippon.tech/modeling-data-with-cassandra-what-cql-hides-away-from-you/

看来静态列可以帮到你!

create table users.user_data (user_id uuid PRIMARY KEY, 
              name varchar static, 
              account_count counter static, 
              some_other_column varchar static,
              account_id uuid, 
              amt int, 
              PRIMARY KEY (user_id, account_id));
  • 原来不属于 user_account 表的列被标记 作为静态
  • 静态列仅在内部存储一次
  • user_id 是分区键,account_id 是集群键Explanation

根据Is this type of counter table definition valid?,计数器列可以是静态的

【讨论】:

  • 感谢你的 cmets Yurii。
  • 提出了一种新的表结构来将所有数据存储在一行中。请分享您宝贵的想法。 create table USER_DATA ( userId uuid PRIMARY KEY, name text, noOfAccounts int, user_accounts Map, // key 是 userAccountId(UUID) 并且 value 是文本格式的 json 有效载荷 user_group_id ); user_account 数据的部分更新。就像更新其中一个用户帐户中的一个特定字段一样。目前我无法实现这一点,只是覆盖整个 user_account(虽然只有一个帐户) Fetch 可以使用 userId 或 userGroupId 发生
  • 可能有更简单的解决方案。请检查上面答案中的更新。不要忘记性能测试并考虑将答案标记为已接受,如果它有助于解决您的问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 2016-10-04
  • 1970-01-01
  • 2015-09-13
  • 2021-01-11
相关资源
最近更新 更多