Cassandra的设计理论倾向于实现CAP原则中的AP(Availability and Partition Tolerance)——高可用性和分布式,它的分布式是基于一致性哈希环(Consistent Hash Ring)算法实现的。 算法
面向行(Row-Oriented) 数据库
咱们经常说Cassandra是一个面向列(Column-Oriented)的数据库,其实这不彻底对——数据是以松散结构的多维哈希表存储在数据库中;所谓松散结构,是指每行数据能够有不一样的列结构,而在关系型数据中,同一张表的全部行必须有相同的列。在Cassandra中可使用一个惟一识别号访问行,因此咱们能够更好理解为,Cassandra是一个带索引的,面向行的存储。 数组
无结构(Schema Free) 服务器
Cassandra只须要你定义一个逻辑上的容器(Keyspaces)装载列族(Column Families),以后,你能够自由地向列族中添加数据。每个列族都被设计为一组数据关联或排列。这种结构意味着,根据你的需求场景,你能够只保存你须要的数据,而没必要拘泥于早前定义的表结构。 数据结构
适用场景(Use Cases for Cassandra) 并发
快速开发应用程序:Schema Free的特色,让Cassandra能够快速适应你的初期变动;若是你使用关系型数据库,那么就不得不从数据表、DAO层、Logic/Service层到UI层进行层层变动,哪怕只是一个小小的列名或字段类型变化; 运维
大量写入、统计和分析:Cassandra的列族设计是囊括数据关联和排序的,而且能够不存储不须要的数据,这极大减省了表联接和冗余字段带来的性能开销,后者偏偏是高并发写入操做、统计分析时关系型数据库的瓶颈; 分布式
须要扩展的部署结构:Cassandra是面向分布式的设计,这让它能够灵活地水平扩展,以在运维阶段知足你的需求,而没必要考虑“将数据迁往更高性能的服务器”这样的问题。 ide
数据模型(Data Model) 高并发
咱们从最基本的概念来理解Cassandra的数据模型,先假设使用一个最简单的值结构来存放一堆数据(Values)。
但问题是,除非咱们记录了每一个值的存放地址,咱们将没法访问到这些数据,这看起来很像一个数组或集合,咱们必须记住某个值的索引号,而且还要预先定义好这个数组的宽度,不然它会没法容纳足够多的数据。
解决办法是为每一个数据添加一个惟一名称(Name),只要咱们记住了这个名称,就能找到这个数据了,这样,咱们就有了一堆名称——值对(Name/Value Pair)。
这个结构很像哈希表,能够知足一些信息的存储,例如用户的基本信息,姓、名、电话、手机、公司、地址等,而且咱们能够根据须要来决定存储哪些名称和值,如此,咱们就获得了一个单独的行(Single Row),并引出了Cassandra数据库中重要的行列概念定义:
一组包含名称值对的数据叫作行(Row),而每一组名称值对(Name/Value Pair)被称之为列(Column)。
在关系型数据库中,列的名称必须是字符串,但在Cassandra中列名称能够为任意类型,这意味着,你能够将列名称也做为一个数据来存储。换一种说法,你没必要被数据类型约束,往Cassandra中添加数据就够了。
下面的示例可让咱们更好地理解Cassandra的数据存储:
Musician: ColumnFamily 1 bootsy: RowKey email: bootsy@pfunk.com, ColumnName:Value instrument: bass ColumnName:Value george: RowKey email: george@pfunk.com ColumnName:Value Band: ColumnFamily 2 george: RowKey pfunk: 1968-2010 ColumnName:Value
另外,Cassandra还有一种可在列之间创建关联的超级列(Super Column),你能够往超级列中添加子列。
键空间(Keyspaces)
键空间是Cassandra的数据容器,能够理解为关系型数据库中的数据库(Database)。对于一个Keyspace来讲,有如下几个属性:
数据复制节点数目(Replication factor ):定义Keyspace中每行数据的复制节点数目,若是定义为三,在哈希环上,每行数据将会有三个拷贝节点,而且都可以被客户端请求到。
复制替换策略(Replica placement strategy):定义在一致性哈希环中某个节点的替换策略。
列族(Column Families):相似于关系型数据库中的表(Table),是列的容器。
列族(Column Families)
上面已经讲到,列族是列的容器,它的结构像是一个四维哈希表:
[Keyspace][ColumnFamily][Key][Column]
若是用JSON表示,一组存放在列族中的数据看起来是这样的:
Hotel { key: AZC_043 { name: Cambria Suites Hayden, phone: 480-444-4444,address: 400 N. Hayden Rd., city: Scottsdale, state: AZ, zip: 85255} key: AZS_011 { name: Clarion Scottsdale Peak, phone: 480-333-3333,address: 3000 N. Scottsdale Rd, city: Scottsdale, state: AZ, zip: 85255} key: CAS_021 { name: W Hotel, phone: 415-222-2222,address: 181 3rd Street, city: San Francisco, state: CA, zip: 94103} key: NYN_042 { name: Waldorf Hotel, phone: 212-555-5555,address: 301 Park Ave, city: New York, state: NY, zip: 10019} }
使用Cassandra建立键空间Hotelier,列族为Hotel,并查询行键(Row Key)为“NYN_042”的结果显示:
cassandra> get Hotelier.Hotel['NYN_042'] => (column=zip, value=10019, timestamp=3894166157031651) => (column=state, value=NY, timestamp=3894166157031651) => (column=phone, value=212-555-5555, timestamp=3894166157031651) => (column=name, value=The Waldorf=Astoria, timestamp=3894166157031651) => (column=city, value=New York, timestamp=3894166157031651)
列(Column)
若是你对“列”的理解来自于关系型数据库,那么很容易产生和我以前同样的误解,觉得Cassandra是把关系型数据库的行列进行了某种倒置而获得的设计。其实不是这样的,Cassandra的列是一组键值对,它的结构以下图所示(事实上,这个数据结构是Cassandra 0.7.0,最新的2.0.3版本中ByteBuffer替代了byte[],long型的日期时间替代了IClock):
使用JSON描述的列结构:
{ "name": "email", "value: "me@example.com", "timestamp": 1274654183103300 }
超级列(Super Column)的结构:
复合键(Composite Keys)
有时咱们会遇到不一样省份可能有一样的城市名称,或不一样的城市有重名的街道,这时使用单一的城市名称或街道名称来做为Key就会没法识别。Cassandra容许你使用Key1:Key2的结构来存储一对值做为Key,一个常见的例子是使用<userid:lastupdate>这样的结构来存储用户ID及最后登陆时间。下面是一个例子:
HotelByCity (CF) Key: city:state { key: Phoenix:AZ {AZC_043: -, AZS_011: -} key: San Francisco:CA {CAS_021: -} key: New York:NY {NYN_042: -} }
最后让咱们来巩固一下Cassandra和关系型数据库的区别吧:
没有查询语言:No SQL (Structured Query Language);
没有外键约束:关系型数据库的最重要特征;
双重簇索引:在关系型数据库中,每一个表只能指定一个簇索引,其它的索引查询都会致使全表扫描,但在Cassandra中,咱们能够有第二级的簇索引;
排序是在设计时决策:Cassandra不支持Order By,排序是须要设计时考虑,而不是像在关系型数据库查询时刻使用Order By;
无数据结构约定:这是Cassandra最大的优点,在关系型数据库中,咱们设计数据库结构时老是慎之又慎,但在Cassandra中不须要预先约定数据结构。
本文参考自《Cassandra: The Definitive Guide》