http://asio.rssing.com/chan-2089672/all_p4.html
Column
Column是Cassandra中最小的数据单元,它是一个三元的数据类型,包含name,value,timestamp.
Column必须有一个名称,类似于JAVA中的字符串,应用创建后可以动态地设置,Column可以在name上建索引。不要求每个name都有对应的value,value可以为空。还有一列是时间戳,标识column最新更新的时间。时间戳是由客户端应用程序提供的,请求到来时总是希望返回时间戳最新的数据,如果多个客户端同时更新相同的列,列值与最近的更新相同。
SuperColumn
ColumnFamily可以是一个常规Column,也可以是一个SuperColumn.可以将SuperColumn想象成Column的数组,它包含一个name以及一系列Column.
注意:SuperColumn本身不包含timestamp属性。使用SuperColumn有一个限制,要读取其中一个子列的值,必须把所有子列都反序列化,且不能在子列中建索引。因此SuperColumn的应用场合是子列数相对较小的情况。
ColumnFamily
相比关系型数据库,Cassandra中的ColumnFamily相当于数据库中的表,它是一个包含了许多行的结构,每一行由Key和这个Key所关联的Column组成。与关系数据库不同的是,每行不要求有相同数目的列。有两种不同的列族设计:静态和动态。
静态ColumnFamily:使用一组不变的列名,这点更像关系型数据库。如下图:
动态ColumnFamily:每一行的列名不相同,是在运行过程中动态计算和设置的。如下图:
ColumnFamily每一行可以是一系列Column,也可以是一系列SuperColumn。
Keyspace
每个Keyspace包含多个ColumnFamily,并且可以指定数据备份策略和备份数。一般一个Cassandra一个Keyspace。
Cassandra 的数据存储结构
Cassandra 的数据模型是基于列族(Column Family)的四维或五维模型。它借鉴了 Amazon 的 Dynamo 和 Google's BigTable 的数据结构和功能特点,采用 Memtable 和 SSTable 的方式进行存储。在 Cassandra 写入数据之前,需要先记录日志 ( CommitLog ),然后数据开始写入到 Column Family 对应的 Memtable 中,Memtable 是一种按照 key 排序数据的内存结构,在满足一定条件时,再把 Memtable 的数据批量的刷新到磁盘上,存储为 SSTable 。
图 1. Cassandra 的数据模型图:
- Cassandra 的数据模型的基本概念:
- 1. Cluster : Cassandra 的节点实例,它可以包含多个 Keyspace
2. Keyspace : 用于存放 ColumnFamily 的容器,相当于关系数据库中的 Schema 或 database3. ColumnFamily : 用于存放 Column 的容器,类似关系数据库中的 table 的概念 4. SuperColumn :它是一个特列殊的 Column, 它的 Value 值可以包函多个 Column5. Columns:Cassandra 的最基本单位。由 name , value , timestamp 组成
下面是关于数据模型实例分析 :
图 2. 数据模型实例分析
各组成部分
在弄明白各个组成部分是如何组织在一起之前,让我们先一一认识它们:
Column
Column是数据增量最底层(也就是最小)的部分。它是一个包含名称(name)、值(value)和时间戳(timestamp)的三重元组。
下面是一个用JSON格式表示的column:
{ // 这是一个Column
name: "emailAddress",
value: "arin@example.com",
timestamp: 123456789
}
就是这样。简洁起见,让我们忽略时间戳,只把它看作一个name/value的对。
另外,需要注意的是,name和value都是二进制的(技术上指byte[]),并且可以是任意长度。
SuperColumn
SuperColumn是指这样一个元组:包含一个二进制的name,value为可以包含无限数量的Column的map —— 使用Column的name作为key。仍然以JSON格式为例:
{ // 这是一个SuperColumn
name: "homeAddress",
// 无限数量的Column
value: {
// 注意,key就是Column的name
street: {name: "street", value: "1234 x street", timestamp: 123456789},
city: {name: "city", value: "san francisco", timestamp: 123456789},
zip: {name: "zip", value: "94107", timestamp: 123456789},
}
}
Column vs SuperColumn
Column和SuperColumn都是拥有name、value的元组。最大的不同在于标准Column的value是一个“字符串”,而 SuperColumn的value是一个包含多个Column的map。这是主要的区别。。。它们的value包含的是不同类型的数据。另一个细微的差 别是:SuperColumn没有时间戳。
继续前进之前
在继续前进之前,我希望通过一些方式来简化我们的示例:1)从Column中去除时间戳 2)将Column和SuperColumn的名称移到外面,这样看上去像一个key/value对。于是我们从:
{ // 这是一个SuperColumn
name: "homeAddress",
// 无限数量的Column
value: {
street: {name: "street", value: "1234 x street", timestamp: 123456789},
city: {name: "city", value: "san francisco", timestamp: 123456789},
zip: {name: "zip", value: "94107", timestamp: 123456789},
}
得到
homeAddress: {
street: "1234 x street",
city: "san francisco",
zip: "94107",
}
分组
有一个简单的结构用来分组Column和SuperColumn。。。这个结构被称作ColumnFamily,并且拥有两种形式:标准的&超级的
ColumnFamily
ColumnFamily是一种可以包含无限数量的行(row)的结构。哈哈,你是说行吗?是的 —— 就是行 :) 为了让你更好的理解,把它(译注:ColumnFamily)想象成关系型数据库中的表。
好的 —— 每一行拥有一个由客户端提供的(也就是你)key,以及一个包含多个Column的map。再强调一次,map中的key是Column的name,value是Column本身:
UserProfile = { // 这是一个ColumnFamily
phatduckk: { // 这是ColumnFamily中这一行的key
// 这一行中无限数量的Column
username: "phatduckk",
email: "phatduckk@example.com",
phone: "(900) 976-6666"
}, // 这一行结束
ieure: { // 这是ColumnFamily中另一行的key
// 另一行中无限数量的Column
username: "ieure",
email: "ieure@example.com",
phone: "(888) 555-1212"
age: "66",
gender: "undecided"
},
}
记住:简单起见,我们只显示了Column的value,但事实上map中的value应该是整个Column。
你可以把它想象成HashMap/字典或关联数组( HashMap/dictionary or associative array)。如果你开始这么想了,那么你就走上正轨了。
需要指出的是:ColumnFamily没有固定模式(schema)。并没有预先定义行包含了哪些Column。在我们上面的示例中,你看到key是 “ieure”的行包含name为“age”和“gender”的Column,然而key是“phatduckk”的行并没有这两个Column。这是 100%灵活的:一个行可能包含1989个Column,而另一行只包含2个Column。一个行可能包含一个称作“foo”的Column,而其它的行 并没有。这就是Cassandra无模式的表现( This is the schemaless aspect of Cassandra)。
ColumnFamily也可以是超级的
现在,ColumnFamily可以有两种类型:标准的 或 超级的
我们刚才看到的示例是标准类型的ColumnFamily。标准类型的ColumnFamily是指所有的行包含的都是标准Column(即不是SuperColumn)的map。。。其中没有SuperColumn。
相反的,一个超级类型的ColumnFamily是指:每一行包含的是SuperColumn的map。这个map用SuperColumn的name作 为key,value是SuperColumn本身。并且,清楚起见,超级类型的ColumnFamily中不包含标准类型的ColumnFamily。 这儿是一个示例:
AddressBook = { // 这是一个超级类型的ColumnFamily
phatduckk: { // 这是Super ColumnFamily中这一行的key
// 这儿的key是地址簿所属人的名字
// 这一行中可以包含无限数量的SuperColumn
// 该行内(译注:每一行包含的是一个map)的key是SuperColumn的名称
// 每一个SuperColumn是一个地址簿的条目
friend1: {street: "8th street", zip: "90210", city: "Beverley Hills", state: "CA"},
// 这是phatduckk的地址簿中被称作John的条目
John: {street: "Howard street", zip: "94404", city: "FC", state: "CA"},
Kim: {street: "X street", zip: "87876", city: "Balls", state: "VA"},
Tod: {street: "Jerry street", zip: "54556", city: "Cartoon", state: "CO"},
Bob: {street: "Q Blvd", zip: "24252", city: "Nowhere", state: "MN"},
...
// 我们可以拥有无限数量的SuperColumn (即地址簿条目)
}, // 这一行结束
ieure: { // 这是Super ColumnFamily中另一行的key
// ieure的地址簿的所有条目
joey: {street: "A ave", zip: "55485", city: "Hell", state: "NV"},
William: {street: "Armpit Dr", zip: "93301", city: "Bakersfield", state: "CA"},
},
}
Keyspace
Keyspace是数据分组的最外层。所有的ColumnFamily都包含在Keyspace当中。Keyspace常常用项目工程名称来命名。
Keyspace可以包含多个ColumnFamily,但这并不意味着它们之间有必然的关系(imposed relationship)。例如:这并不像MySQL中的table。。。你不能对它们做关联(join)。这是因为假设ColumnFamily_1 有一个key为“phatduckk”的行,并不意味着ColumnFamily_2也有key为“phatduckk”的行。