Cassandra数据模型
译者:陆志忠 原文:http://wiki.apache.org/cassandra/DataModel
介绍
Cassandra数据模型是通过四维或五维Hash实现的
其基本组成:
Cluster:机器(节点)在一个逻辑Cassandra实例。Clusters能够包含多个keyspac es。
Keyspace: ColumnFamilies命名空间,通常每个应用有一个。
ColumnFamilies包含多个Column,每个Column有名字,值和时间戳,它被每行(Row)的Key应用。
SuperColumns也是一种Column,本身有很多子Column。
我们将从下到上开始讲,即从树的叶子节点(Cassandra的数据结构(column))往上到树的根结点(Cluster)
Columns
Column是系统中增加的数据最小的单位,它包含三部分:name, value和timestamp
下面是一个简单的Column接口(注:结构)定义
struct Column{
1:binary name,
2:binary value,
3:i64 timestamp,
}
JSON数据的表示方式:
{
"name":"emailAddress",
"value":"lzz313atgmail.com",
"timestamp":12345678
}
所有的值都是由client提供,包含‘timestamp'. 这就意味着client端的时钟应该被同步(在Cassandra服务器端同步也是非常有用的),这里的时间戳(timestamp)是用来解决冲突的。 在客户端的很多情况下‘timestamp’是不会被使用的,根据时间戳能方便的找到Column的name/value。
在文档的剩下部分,‘timestamps'将被省略,另外name和value是二进制值,在许多应用程序中把他们序列化为UTF-8的字符串。
Timestamps能够做你任何想做的事,是一个从1970开始的毫秒数,在Java中使用System.getTimeMillis()方法获得。无论你什么时候使用,它必须在交叉的应用中一致否则可能之前改变的可能覆盖最新的。
Column Families
一个Column Family是很多Column的容器(注:集合),类似关系系统中的表(table)。可以在你的storage-conf.xml文件中定义column families,且在Cassandra进程没有重新启动的情况下不能改变他们(或添加一个新的Column Families)。 Column family是一个column的有序列表,是通过name来排序的。
Column families每行上的列都可以应用一个可配置的排序,它会影响调用了get_slice的thrift API。ASCII,UTF-8,Long 和UUID(词汇和时间)上可以实现开箱即用的排序。
Rows
在Cassandra系统中,每个column family被存储在不同的文件里,这些文件是按照row上的主要order(注: 主要的排序键)(i.e. key)来排序的。相关的columns中你将一起访问,应该被保存在相同的column family中。
Row的key是决定了存储在机器上的数据。因此你可以根据每个key从多个与之相关column families上获取到数据。但是这些在逻辑上来说是不同的,这就是为什么thrift interface获取数据的时候在同一个时间里每个key只有一个column family。(TODO given this, is the following JSON more confusing than helpful?)
JSON表示key -> column families -> column structure
{ "mccv":{ "Users":{ "emailAddress":{"name":"emailAddress", "value":"lzz313atgmail.com"}, "webSite":{"name":"webSite", "value":"http://blog.csdn.net/lzz313"}
}, "Stats":{ "visits":{"name":"visits", "value":"243"} } }, "user2":{ "Users":{ "emailAddress":{"name":"emailAddress", "value":"10061@hipicube.com"}, "twitter":{"name":"hipikids", "value":"10061"} } } }
注意“mccv”的关键数据在两个不同column families里面,“Users"和“Stats".这并不意味着数据和这些column families相关。相同的key在不同的column families取决于应用程序。另外要注意的是有“Users” column family,“mccv”和“user2”有被定义为不同的column名字。这在Cassandra系统中是完全有效的。事实上这儿可以定义有许多虚拟的无限制的column名字,从而导致很多在用普通的column名字作为一个运行时的数据块。这是一个不寻常的存储系统,特别是对一直在使用RDBMS系统的人来说。
Keyspaces
Keyspace是Cassandra第一维hash,是column families的容器(container)。Keyspaces和RDBMS系统中的schema或database(i.e 一个逻辑集合的tables)有几乎相同的粒度。他们可以对column families进行配置和管理,也是一种可以用于批量insert的结构(structure).
Super Columns
到现在为止,我们已讲了正常的 columns和rows。Cassandra 也支持超级columns(super columns):columns的值也可以是超级columns;一个超级column是由一个(已排序)的数组构成。
因此我们想到columns和super columns在map上:row在普通的column family是基本上是一个已排序的column名字到column值的map;row在一个super column family是一个已排序的super column map,这个super column也是一个已排序的column名字到column值的map。
JSON描述:
{ "mccv": { "Tags": { "cassandra": { "incubator": {"incubator": "http://www.hipikids.com"}, "hipikids": {"hipicube": "http://hipicd.hipicube.com"} }, "thrift": { "hipikids": {"hipicube": "http://hipicd.hipicube.com"} } } } }
这儿我的column family是“Tags”。我定义了两个super columns:“cassandra"和“thrift"。 这些特定的命名的bookmarks中每个都是一个column。
就像普通的column,超级column是稀疏(sparse):每行(row)包含尽可能多或尽可能少;Cassandra并没有限制。
范围查询(Range queries)
Cassandra可以用相对少量的代码支持可插入分区(partitioning scheme)。开箱即用,Cassandra提供基于hash的RandomPartitioner和OrderPreservingPartitioner。
RandomPartitioner 提供了不错的负载均衡,另一方面OrderPreservingPartitioner让你可以在所存储的key的某一范围内查询,但是需要仔细的选择节点或主动做负载均衡。
对于仅支持基于hash的分区不支持高效率的范围查询,
Modeling your application 不像关系系统,你的model实体和实体之间关系通过添加索引来支持一切有必要的查询,在Cassandra系统中你必要想一下支持有效率的查询的适当的model,由于没有自动索引,你的每个查询应该比关系查询中的表会更接近于 columnfamily,不要害怕反模式;Cassandra比关系系统中的写操作快很多很多。 Arin Sarkissian的Digg中有一篇非常优秀的Cassandra's data model并且详细举例说明。 当你设计model的时候要参考CassandraLimitations 例子:SuperColumns for Search Apps 你可以把每个super column名字想像为一个词语(term),它包含一个docId,等级信息,和其他属性。如果你用userid作为key,这时你可以以这种形式为每个用户的存储索引。这就是Facebook怎样从Inbox通过索引找出每个用户方法。 此外,存储数据在磁盘上按“Time”排序的,系统可以很容易的查处“给我10个最新的消息”。有关图解请参考在SIGMOD 2008的Cassandra ppt。 Example:multiuser blog TODO Thrift API 移到 API。 Attribution 感谢phatduckk和asenchi对于例子,文字的审查。