锁定老帖子 主题:对Cassandra的初体验
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-10-13
最后修改:2010-10-14
在啥都不清楚的情况下,首先选择跟风,未必是一件坏事。尤其对技术人员而言,先入门再做选择,也不失为一种方法。“听说xxx大网站都是用Cassandra存储他们的SNS数据的,我们也要试试”,于是乎,开始了Casssandra初体验。 (PS:本文不是cassandra的入门学习的材料。以下均为笔者自己的理解,一家之言,不正确的地方,望指正...) 以OO的方式理解Cassandra的数据模型 学习Cassandra,首先要理解它有别于传统数据库的存储模型。对于常使用HashMap的Java程序员而言,K-V的映射结构并不难理解。 把Cassandra的ColumnFamily看成HashMap 网上有不少文章认为ColumnFamily类似RDB中的Table,这样理解有一定道理,但笔者更愿意从OOD的角度去诠释它。从Cassandra的设计实现上看,把它理解为大型的散列结构的索引更贴近其本来面目。 ColumnFamily中的K-V映射 ColumnFamily中的K-V映射有两大类型:
针对第一种单层映射,从OOD角度看,笔者理解为 1 Key --> 1 Javabean的标准HashMap映射。你完全可以把“n个Column”理解为直接暴露在外的Bean的n个属性。 而对于第二种的两层映射,笔者认为是 1 Key --> Bean列表 的 1对n 映射。这里,你可以把“1个SuperColumn”--->“n个SubColumn”的映射,理解为 1个Bean 对 n个属性的映射封装;把“1个key” ---> “n个SuperColumn”,视为 Key 对 Bean 的一对多映射,即 Key 映射 一个Bean列表。 之所以笔者使用对象模型视角,而不是数据库的行列模型视角来看待Cassandra,是有以下原因的:
Column的排序与组织 在Cassandra中,给出Column/SuperColumn的排序方式是十分重要的事。事实上,在你定义ColumnFamily时,你是无需定义其包含了那些Column/SuperColumn,而更重要的是定义Column/SuperColumn的排序方式。这里,笔者根据自己的理解做以下的判断:
Cassandra数据的Json表现 为了让各位看官更直观的体验Cassandra的数据结构,增加以下的Json表现部分: 1.单层映射(Column)的JSON格式 { "mccv":{ "Users":{ "emailAddress":{"name":"emailAddress", "value":"foo@bar.com"}, "webSite":{"name":"webSite", "value":"http://bar.com"} }, "Stats":{ "visits":{"name":"visits", "value":"243"} } }, "user2":{ "Users":{ "emailAddress":{"name":"emailAddress", "value":"user2@bar.com"}, "twitter":{"name":"twitter", "value":"user2"} } } } 其中 “mccv”,“user2” 是key ; “Users”,“Stats”是ColumnFamily, “emailAddress” , “webSite”,“visits”等是Column。 1.二层映射(SuperColumn)的JSON格式 { "mccv": { "Tags": { "cassandra": { "incubator": {"incubator": "http://incubator.apache.org/cassandra/"}, "jira": {"jira": "http://issues.apache.org/jira/browse/CASSANDRA"} }, "thrift": { "jira": {"jira": "http://issues.apache.org/jira/browse/THRIFT"} } } } } 其中 “mccv”为key ;"Tags"为ColumnFamily ;“cassandra”,“thrift” 为SuperColumn ; “incubator”,“jira” 为 subColumn. 以OO的方式使用Cassandra Cassandra官方提供了thrift作为其客户端的API,但我们发现它是面向Column的“底层化”操作。这无疑对习惯了以为Bean操作单元的Java开发者而言,是一个痛苦的思维转化过程和代码实现。 好在我们在其官网发现了一个受推荐的,相对高级的Java客户端,也就是笔者要推荐的“Pelops”。该API提供了对ColumnFamily的整体性操作,并且还提供了类似翻页,排序的实现。 在“Pelops”基础上, 我们通过简单的、对JavaBean属性的类反射封装,实现了类似Hibernate式的Bean的存储访问(而不再是Bean的属性对应一个Column的读写),这让笔者的心情大为舒畅 。 Pelops的一点小插曲 笔者在使用Pelops的过程中,发生了一些小插曲:在系统正式发布时,Cassandra的访问账户必须有安全限制的(就是要有用户名、密码认证)。然而,找遍了Pelops的API,却发现它没有提供用户名、密码的配置方法(晕死啊!!!不知道是不是笔者没找到),最后不得已,对其源码进行了简单的修改。 以下是被笔者修改的两个类: 1.org.wyki.cassandra.pelops.Policy. 这个类只是简单的添加了username 、 password、 keyspace三个属性,以及对应的get,set方法,通过它将账户配置信息传入链接池。 2.org.wyki.cassandra.pelops.ThriftPool. 这个是 pelops的链接池类,笔者修改了其中的私有方法createConnection(),使得在创建链接的时候,带上用户名密码的安全认证信息 private Connection createConnection() { Connection conn; try { conn = new Connection(this, defaultPort); } catch (SocketException e) { e.printStackTrace(); return null; } if (conn.open(sessionId.get())){ // **** add by linliangyi *** Policy police = getPolicy(); if(police.keyspace != null && police.username != null && police.password != null){ Map<String , String> userNamePassword = new HashMap<String , String>(); userNamePassword.put(SimpleAuthenticator.USERNAME_KEY, police.username); userNamePassword.put(SimpleAuthenticator.PASSWORD_KEY, police.password); try { conn.getAPI().login(police.keyspace , new AuthenticationRequest(userNamePassword)); } catch (AuthenticationException e) { e.printStackTrace(); return null; } catch (AuthorizationException e) { e.printStackTrace(); return null; } catch (TException e) { e.printStackTrace(); return null; } logger.trace(police.keyspace + " | " + police.username + " | " + police.password); } return conn; } return null; } 至此,笔者对Casssandra初体验告一段落。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-10-14
看来是用Cassandra的兄弟还是较少啊,用其他KV数据库的同学也说说各自的使用感受啊~~~
|
|
返回顶楼 | |
发表时间:2010-10-14
linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? |
|
返回顶楼 | |
发表时间:2010-10-14
最后修改:2010-10-14
myreligion 写道 linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? 楼上的说的很对,不能将过多的列放在subColumn中,否则容易OOM。 应该使用第一级别的映射,也就是说,将用户ID作为Key,将fans作为Key对应的多个Column。在这个层级上是不会一次性持久化的,但SuperCloumn就会。 |
|
返回顶楼 | |
发表时间:2010-10-14
linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? 楼上的说的很对,不能将过多的列放在subColumn中,否则容易OOM。 应该使用第一级别的映射,也就是说,将用户ID作为Key,将fans作为Key对应的多个Column。在这个层级上是不会一次性持久化的,但SuperCloumn就会。 1个用户会有很多东西,除了fans,还有关注的人,还有短消息,还有动态,XXX。这样岂不是1个人要拥有很多个key?然后显示个人首页的时候,把N多key一个个查,在合并。感觉这样也不对,1个用户的信息应该在1个key下,在这个key下面在按照树状结果无限分下去,Cassandra只允许两层树结构限制太大了。。。 |
|
返回顶楼 | |
发表时间:2010-10-14
myreligion 写道 linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? 楼上的说的很对,不能将过多的列放在subColumn中,否则容易OOM。 应该使用第一级别的映射,也就是说,将用户ID作为Key,将fans作为Key对应的多个Column。在这个层级上是不会一次性持久化的,但SuperCloumn就会。 1个用户会有很多东西,除了fans,还有关注的人,还有短消息,还有动态,XXX。这样岂不是1个人要拥有很多个key?然后显示个人首页的时候,把N多key一个个查,在合并。感觉这样也不对,1个用户的信息应该在1个key下,在这个key下面在按照树状结果无限分下去,Cassandra只允许两层树结构限制太大了。。。 我的理解是,cassandra相对与数据库而言,实际是一个相对底层的索引机制。 不清楚其他的用户是如何设计的,但我自己用起来,是对不同的信息建不同的ColumnFamily的,这就跟建表一个道理。 在传统RDB中,你不会把关注,fans,短消息,动态。。。都放一张表里吧 |
|
返回顶楼 | |
发表时间:2010-10-14
介绍的真的很不错,希望能出更多的好文跟大家分享
|
|
返回顶楼 | |
发表时间:2010-10-14
linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? 楼上的说的很对,不能将过多的列放在subColumn中,否则容易OOM。 应该使用第一级别的映射,也就是说,将用户ID作为Key,将fans作为Key对应的多个Column。在这个层级上是不会一次性持久化的,但SuperCloumn就会。 1个用户会有很多东西,除了fans,还有关注的人,还有短消息,还有动态,XXX。这样岂不是1个人要拥有很多个key?然后显示个人首页的时候,把N多key一个个查,在合并。感觉这样也不对,1个用户的信息应该在1个key下,在这个key下面在按照树状结果无限分下去,Cassandra只允许两层树结构限制太大了。。。 我的理解是,cassandra相对与数据库而言,实际是一个相对底层的索引机制。 不清楚其他的用户是如何设计的,但我自己用起来,是对不同的信息建不同的ColumnFamily的,这就跟建表一个道理。 在传统RDB中,你不会把关注,fans,短消息,动态。。。都放一张表里吧 这样子很方便,效率也高。我觉得其实可以折中下,把用户零碎的一些信息,如资料,fans数,关注数,最新动态,最近访客等等放到一个key下,其他大的东西放到各自的key下。如果访问首页,就直接从这个key下读到所有东西了,如果继续点别的,再从别的key下取东西。您觉得这样如何? cassandra如果能提供无限树结构就好办了,类似于早年的树型数据库。RDB自然不会这样设计,但cassandra是新东西,总要有点新期待吧 |
|
返回顶楼 | |
发表时间:2010-10-14
myreligion 写道 linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 myreligion 写道 linliangyi2007 写道 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。~~~
在sns中,这样是不是说将一个用户存储成一个SuperColumn,而这个用户的fans存储成1个subColumn(只存储用户名)。如果这个人有几十万甚至几百万的fans,那么读取fans的时候全部序列化岂不是疯掉了?还是我不能这样设计? 楼上的说的很对,不能将过多的列放在subColumn中,否则容易OOM。 应该使用第一级别的映射,也就是说,将用户ID作为Key,将fans作为Key对应的多个Column。在这个层级上是不会一次性持久化的,但SuperCloumn就会。 1个用户会有很多东西,除了fans,还有关注的人,还有短消息,还有动态,XXX。这样岂不是1个人要拥有很多个key?然后显示个人首页的时候,把N多key一个个查,在合并。感觉这样也不对,1个用户的信息应该在1个key下,在这个key下面在按照树状结果无限分下去,Cassandra只允许两层树结构限制太大了。。。 我的理解是,cassandra相对与数据库而言,实际是一个相对底层的索引机制。 不清楚其他的用户是如何设计的,但我自己用起来,是对不同的信息建不同的ColumnFamily的,这就跟建表一个道理。 在传统RDB中,你不会把关注,fans,短消息,动态。。。都放一张表里吧 这样子很方便,效率也高。我觉得其实可以折中下,把用户零碎的一些信息,如资料,fans数,关注数,最新动态,最近访客等等放到一个key下,其他大的东西放到各自的key下。如果访问首页,就直接从这个key下读到所有东西了,如果继续点别的,再从别的key下取东西。您觉得这样如何? cassandra如果能提供无限树结构就好办了,类似于早年的树型数据库。RDB自然不会这样设计,但cassandra是新东西,总要有点新期待吧 我在原文中补充了cassandra的json数据结构,你看一下,事实上cassandra的数据组织是跟符合你的意愿的,但你需要声明不同的ColumnFamily来区隔数据。 实际上cassandra是采用树形结构的,但是,SuperColumn就实现而言,显然是针对一个完整对象的序列化设计的。如果你只是把cassandra当成简单的列化的RDB使用,也是可以的,当然你就必须考虑上述的系列化中的性能问题。 |
|
返回顶楼 | |
发表时间:2010-10-14
用户动态信息用neo4j.
|
|
返回顶楼 | |