本文介绍Cassandra数据建模的概念、建模建议。

Cassandra是一款分布式、去中心化、高可用的列存储(Wide Column Store)的No SQL数据库。分布式层面主要依靠一致性Hash算法把数据分布在整个集群中,单机主要实现了基于LSM-Tree的引擎。

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

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

需要了解的概念

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

CREATE TABLE mytable1 ( name text PRIMARY KEY , age int , address text , persion_id text );
CREATE TABLE mytable2 ( name text , age int , address text , persion_id text, PRIMARY KEY (name, age) );
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
  • partition key :partition key是PRIMARY KEY的第一列,定义了Cassandra数据在通过Hash以后分布在哪个具体的节点。上述例子中,mytable1、mytable2、mytable3的partition key分别是name、name、(name, age)。拥有相同partition key的数据一般会存在一个分区下面。
  • clustering key :clustering key是PRIMARY KEY除partition key的后续列,定义数据在同个分区下面的顺序。上述例子中,mytable1没有clustering key;mytable2、mytable3的clustering key分别是age、persion_id。

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

    以下述为例:

    CREATE INDEX mytable_idx_age ON mytable2 (age) ;

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

    CREATE TABLE mytable_index_age (age int,name text , address text , persion_id text,PRIMARY KEY(age, name))

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

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

    SELECT * FROM mytable2 WHERE age = 11 AND name = 'name';
    SELECT * FROM mytable2 WHERE age >= 11 AND name IN ('name1', 'name2') ;
    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 (实验性质的功能),所以使用前需要谨慎考虑。