全部产品

Cassandra数据建模

更新时间:2020-06-19 14:58:38

Cassandra是一款分布式、去中心化、高可用的Wide-column 的Nosql,分布式层面主要依靠一致性HASH算法把数据分布在整个集群中,单机主要实现了基于LSM-Tree的引擎.

屏幕快照 2020-03-09 19.04.40.png集群中的每个节点将整个HASH范围均匀的分担,每个节点即当做proxy节点,接受client的请求,也负责集群的Primary key range的数据,依赖集群的keyspace的副本策略以及集群的snitch策略,Cassandra将各个节点负责的primary key range 复制到集群中其他节点,以提高分布式系统中数据可靠性以及服务可用性.

同时每次读写在Cassandra中都会定义ConsistencyLevel(也就是我们说的ONE/TWO/QUORUM等级别),通过这些可调一致性的级别Cassandra兼顾了服务可用性以及单次请求的数据一致性.

需要了解的概念

Key的概念

Cassandra中有多个key的概念需要了解,以下述例子进行描述:

  1. CREATE TABLE mytable1 ( name text PRIMARY KEY , age int , address text , persion_id text );
  1. CREATE TABLE mytable2 ( name text , age int , address text , persion_id text, PRIMARY KEY (name, age) );
  1. CREATE TABLE mytable3 ( name text , age int , address text , persion_id text, PRIMARY KEY ((name, age), persion_id) ) WITH CLUSTERING ORDER BY (persion_id DESC );
  • PRIMARY KEY : 一行数据的唯一标识,由多类数据组成;上面例子中的name/(name, age)/((name, age), persion_id) 分别都标识了mytable1、mytable2、mytable3的PRIMARY KEY.
  • partition key : partition key定义了Cassandra数据在通过hash以后分布在哪个具体的节点,在我们的例子中,mytable1、mytable2、mytable3的partition key分别是:name、name、name和age组成的key;拥有相同partition key的数据一般会存在一个partition下面;
  • clustering key : 定义数据在同个partition下面的顺序;上述例子中,mytable1没有,mytable2、和mytable3的clustering key 分别是:age、persion_id;当然也可以上述例子3种控制clustering key的升降序.

为了发挥Cassandra集群的性能,我们需要尽量保证集群各个节点的数据量是均匀的。考虑的因素包括partition size、数据冗余度、磁盘占用空间等,其中基于最优的性能考虑,建议每个partition下面的数据条数不超过10万,每个partition下面的数据量不超过100MB。

二级索引

首先还是从一个例子出发,看下我们的案列:

  1. CREATE INDEX mytable_idx_age ON mytable2 (age) ;

在上述的mytable2上面的列 age 中建一个native secondary index,因为Cassandra的native secondary index最终是把索引数据放在一张新表,以建索引列的value为key,以索引的原来的key为value,比如上述我们最终的索引表的表结构可能就是:

  1. CREATE TABLE mytable_index_age (age intname text , address text , persion_id textPRIMARY KEY(age, name))

但是这里的索引表的partition key 是不能够让我们根据age找到具体存放索引表的节点,因为索引表的索引数据和原生数据是放在一个节点,使用的是local数据摆放策略。

所以这里建议我们使用native secondary index的时候加上原表的partition限定,这样是最高效的,否则在没有限定partition key的前提下,我们的查找将会涉及到几乎全表扫描的情况。推荐使用如下的使用模式:

  1. SELECT * FROM mytable2 WHERE age = 11 AND name = 'name';
  2. SELECT * FROM mytable2 WHERE age >= 11 AND name IN ('name1', 'name2') ;
  3. SELECT * FROM mytable2 WHERE age = 11 AND TOKEN (name)> xxxxx AND TOKEN(name) < yyyyy;

数据模型建立建议

在进行操作Cassandra之前需要基于我们对Cassandra的使用进行业务建模,基于我们的引用具有什么特性延伸到如何组织Cassandra的数据(设计primary key)到最终数据在cassandra上的存取。

  • No join:Cassandra不支持join,如果你需要用到join,要么自己在client处理,要么在cassandra中新建一个表进行处理;
  • No referential integrity: 不支持跨表引用完整性的概念,不支持在某个表中通过外键引用另一张表数据;
  • Denormalization: 反范式化;
  • Query-first的设计:和RDBMS不同的是,优先考虑的是基于query进行设计,而不是类似关系数据库那样的需要优先设计模型;
  • Designing for optimal storage:关系型数据库表如何存储是对用户透明的,但是Cassandra的建模需要考虑到数据在磁盘上的存储规则,需要尽量让数据分布的partition少。
  • Sorting is a design decision : 查询上的排序是在建表时候设定好的。

注意:

Cassandra materialized views(物化视图)和sasi indexes被官方标注 EXPERIMENTAL FEATURES (实验性质的功能),所以使用前需要谨慎考虑。