Cassandra 数据模型 (基于CQL,解决胖列数量限制及灵活性问题)(1.1及以上版本)
由于Cassandra版本数次更新,网上中文的资料已经有点过时,比较有代表性的比如ebuy那篇文章都已经过时了,于是自己找资料,结合官方博客写一篇Cassandra模型的文章。
一些名词的介绍:由于技术名词冲突,BigTable里的表对应的是Cassandra里的列族,而BigTable里面列族的概念更类似Cassandra早期实现里的超级列(该功能在Cassandra里已被关闭)。
Cassandra介绍
首先介绍一下Cassandra。
Cassandra是Apache的开源项目,是NoSQL的一种,广泛意义上的列族数据库,分布式,无中心机。其早期实现主要参考了Google的Big Table论文及亚马逊的Dynamo论文中的介绍,可以参考两篇论文来获得Cassandra的设计思想,关于更详细的资料,可以参见wiki及官方文档。
早期实现及最佳实践
前文提到早期实现,那么现在当然与早期区别已经极大了,从数据模型设计到实际使用,基本上已经自成体系了。其中之一最大的改变,就是1.1版本里对数据库操作的改变。
Cassandra的早期实现里,使用的完全是BigTable的数据模型,即列及列族及主键等概念。在ebuy的最佳实践的文中,对该模型的使用做了详细解释,我无意在此引用他人文章,只是简单说一下概念。
最佳实践文章总共分两部分,上部分主要说的是列族数据库中该如何设计数据模型,其中主要讨论的是对关系及部分相关数据的重复储存来减少对数据库的分布式读取,其中对列族数据库数据结构的有个挺有意思的式子,如下:
Map<RowKey, SortedMap<ColumnKey, ColumnValue>>
下部分交代的则是Cassandra中的具体实现方式,比如当时Cassandra实现了一个与BigTable列族类似的东西,或者说只是名字不同的东西,就是超级列,把类似的列聚 合在一起提取。
再比如说推荐使用胖列(使用列键查询)而不是瘦列(使用主键查询)。胖列指的是以大量的列储存关系,比如用户表users有三列user_k,p1,p2,第一列user_k是主键,第二列p1是用户购买的产品1,第三列p2是用户购买的产品2,pn可以扩展到极大的数量.
注:上文只是简单解释,实际全文中对各种应用场景的讨论不仅限于该范围。
磁盘储存方式
Cassandra使用的方式是:把一级主键当做分区主键,列名作为列键储存。光说不清楚,上图:(图片来自Cassandra 1.1)
CREATE TABLE timeline ( user_id varchar, tweet_id uuid, author varchar, body varchar, PRIMARY KEY (user_id, tweet_id) );
上图是传统数据库的储存方式。
上图是Cassandra的储存方式,注意{1787,author}是列键名而不只是数据。
现在的实现
随着Cassandra的成长,原先完全按照BigTable实现的数据模型开始产生一些问题,其中之一就是无法无限扩大的列的数量,虽然已经设计了一个足够大的列数量,但对于大数据分布式数据库,仍然是不够用的,而且超级列的方式灵活性受限制,于是开发者开始走自己的道路,于是随着CQL(Cassandra自己的类似SQL的操作语言)的发布及发展,首先清除了超级列(BigTable里的列族)的概念:在CQL中,没有超级列的概念,在列上一级就是表,也就是原先概念上的超级列是不存在的,那针对原先的胖列的应用场景,该如何处理呢?
CQL中有主键及二级主键的概念,主键就是原先的主键,这个概念没有变化,而对于原先的超级列聚合,CQL通过把二级主键的值加上列名作为列键名解决了这个问题。
也就是说,把原先由数据字典(请允许我使用这个关系数据库词汇)储存的数据储存到了数据表中,减轻了对数据字典的访问及数据字典数据结构的维持开销,把压力下发到数据表。
参考: