Basic Rules of Cassandra Data Modeling

http://www.datastax.com/dev/blog/basic-rules-of-cassandra-data-modeling


Basic Rules of Cassandra Data Modeling


正确掌握cassandra的数据模型不是一件容易的事情,如果你有关系型数据库的背景,col会看上去熟悉一点,但是使用它的方式会很不同。这篇文章的主要目标是使设计cassandra的schema原则牢记于心。如果你遵从这些原则那么你将得到非常好的性能。更好的是,如果你在集群中增加节点,你将得到性能的线性增长。


不需要的目标

来自关系型数据库的开发者往往会把关系型数据模型的一些规则带到cassandra中。但是这些在cassandra中往往不适用。

最小化写原则

写在Casanova当中并不是免费的,但是它非常的廉价。Casanova在高吞吐量写上面有很好的性能,如果你更倾向于用额外的写来获得更好的读性能,那么这会是一个好的方式。因为读往往比写开销更大。

最小化的数据冗余规则

在cassandra中不要害怕数据冗余,硬盘资源往往少最便宜大,并且cassandra的架构正是围绕着这一个事实。为了得到更好的读效率,你往往需要数据冗余。


除此之外,cassandra不支持joins操作。


基本但目标


1,把数据均匀分布在集群当中

2,减少分区读取的个数


上面是两个最基本也是最重要的规则需要铭记在心。除此在外还有其他的一些技巧,但是这些技巧使用的时候你需要好好评估一下。


1,把数据均匀的分布在集群中

你希望在集群中每个节点包含大致相同的数据量,cassandra达成这一目标很简单。rows根据partition key(也就是表中的primary key的第一个字段)的hash来分布在集群中,因此首先要考虑的原则就是primary key。因此要想使数据均匀的分布在集群中,首先是要挑选一个合适的primary key。


2,减少分区读取的个数

分区是一些具有相同partition key的rows的集合。当你要执行一个查询操作,应该尽量少多读区分区的个数。每个分区可以驻留在不同到节点上。协调器通常需要把命令发送到不同到节点上的多个分区。这增大了负载和延迟。不仅如此,即使只在一个节点上,从多个分区读也比从一个分区读更加的开销大。


上面两个原则是有些冲突的,因此需要平衡。


数据模型的设计依赖于你的查询。

减少读取分区个数的查询操作的原则是使你的数据模型更加适合于你的查询。而不是按照关系型建模,不是按照对象的原则建模。


步骤一,决定你将要支持何种查询

比如说,

grouping by an attribute

ordering by an attribute

根据某些条件进行过滤

强制返回唯一的结构


步骤2,创建一个可以使你的查询只读取一个分区的表

在实际中,这通常意味着你的一个表只能去匹配一种查询模型,如果你有多种查询模型,那么你需要多个表


例子1,用户查询

步骤1,决定你需要支持哪种类型的查询

需要添加username或者是邮箱来查询user的详情


步骤2

每一个查询模型对应一个表

create table users_by_username (

username text PRIMARY KEY,

email text,

age int

)


create table users_by_email (

email text PRIMARY KEY,

username text,

age int

)


再让我们看一种不好的设计

create table users (

id uuid PRIMARY KEY,

username text,

email text,

age int


create table users_by_username(

username text PRIMARY KEY,

id uuid


create table users_by_email(

email text PRIMARY KEY,

id uuid

)

上面的数据模型,可以使数据均匀的分布在集群中,但是我们需要读取两个分区,两次查询才能够得到详情结果。


例子2 User groups

我们需要查询一个组内的所有用户


步骤1,

我们需要查询一个组内的所有用户,用户但顺序并不关心。

步骤2,

可以使用一种组合的primary key(其中group name味partitioning key ,username为clustering key

create table groups (

group name text,

username text,

email text,

age int,

PRIMARY KEY (groupname ,username)

)

上面的设计可以查询只读取一个分区,但是它并不能很好的使数据均匀的分布在集群中,如果你有几百万个小的group(每个组内有几百个user)它将会工作的很好(分布的很好),但是如果你的一个组内有几百万个user那么整个重担将由一个节点上(或一套副本)。


如果你想使负载分布的更加均匀一些,那么一个基本的技术是在primary key 增加一个列,组成合成的key,如:

create table groups (

gropuname text,

username text,

email text,

age int,

hash_prefix int,

PRIMARY KEY ((group name ,hash_prefix),username)


hash_prefix的值为usrname取hash的一个前缀。比如,它可以是usrname按4取模的第一个字节,这会把一个分区分为4个分区(因为余数可能说0,1,2,3嘛),那么上述多两个规则也就发生来冲突,因此如果你的读非常多,并且group不是那么大,可以把模由4变为2。另一方面,如果你的读很多并且组很大,那么可以把模由4变为10.



还有一种方法,可以分割partition。思考上面的例子我们冗余了user好多次(每一个组内一次),因此你可能会想减少这种冗余:

CREATE TABLE users (

    id uuid PRIMARY KEY,

    username text,

    email text,

    age int

)

 

CREATE TABLE groups (

    groupname text,

    user_id uuid,

    PRIMARY KEY (groupname, user_id)

)


假如一个组内有1000个用户,上面的这种设计可能会导致我们读取1001次分区才能把分区内的数据全部拿出。当然查询特别不频繁的情景下可能就会不同。




Example 3: User Groups by Join Date

得到一个组内的最新说n个user

我们可以创建下面的表


CREATE TABLE group_join_dates (

    groupname text,

    joined timeuuid,

    username text,

    email text,

    age int,

    PRIMARY KEY (groupname, joined)

)

增加了一个timeuuid类型的字段,这样我们就可以根据用户加入组的时间进行排序了,查询sql如下:


SELECT * FROM group_join_dates

    WHERE groupname = ?

    ORDER BY joined DESC

    LIMIT ?


除此之外,还可以在建表的时候采用更加高效的方式来查询,如下:

CREATE TABLE group_join_dates (

    groupname text,

    joined timeuuid,

    username text,

    email text,

    age int,

    PRIMARY KEY (groupname, joined)

) WITH CLUSTERING ORDER BY (joined DESC)


SELECT * FROM group_join_dates

    WHERE groupname = ?

    LIMIT ?




当然,为什么防止一个组内的数据特别的多,还可以按时间分区如下(每天产生一个新分区)


CREATE TABLE group_join_dates (

    groupname text,

    joined timeuuid,

    join_date text,

    username text,

    email text,

    age int,

    PRIMARY KEY ((groupname, join_date), joined)

) WITH CLUSTERING ORDER BY (joined DESC)

总结

除了上面说的这些原则,当然还有一些其他的问题,比如说 dealing with tombstones 但是这些问题可能会在cassandra将来的版本当中得到解决。


还有其他的一些特性,如collections user-defined types 和static columns都可以减少查询patitions的个数。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值