`
linliangyi2007
  • 浏览: 1004253 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

对Cassandra的初体验

阅读更多
    作为“云计算”时代的架构设计人员而言,不懂K-V库会被人说out的,为此,笔者在“人云已云”的忽悠下,也开始接触K-V数据库了。

    在啥都不清楚的情况下,首先选择跟风,未必是一件坏事。尤其对技术人员而言,先入门再做选择,也不失为一种方法。“听说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映射有两大类型:
  • 1.基于Column的 “1个Key” --->“n个Column” 的单层映射
  • 2.基于SuperColumn的 “1个key” ---> “n个SuperColumn” ,“1个SuperColumn”--->“n个SubColumn”的两层映射

    针对第一种单层映射,从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,是有以下原因的:
  • 首先,Cassandra设计以Key为主导的数据映射寻址机制有别于以“ResultSet结果集”为主的传统RDB数据获取模式。
  • 其次,从Cassandra数据的持久化实现上看,对于一个SuperColumn的读取和存储,Cassandra是采用了一次性序列化的。也就是说,即便你只访问SuperColumn下的1个SubColumn的值,Cassandra也需要把这个SuperColumn下的所有SubColumns都读出,一次性进行反序列化,而后返回你要单个属性列。从这点上看,笔者认为Cassandra的设计者是将SuperColumn视为整体的一个持久化对象(一个完整的JavaBean)来看待。


Column的排序与组织
    在Cassandra中,给出Column/SuperColumn的排序方式是十分重要的事。事实上,在你定义ColumnFamily时,你是无需定义其包含了那些Column/SuperColumn,而更重要的是定义Column/SuperColumn的排序方式。这里,笔者根据自己的理解做以下的判断:
  • 1.ColumnFamily与RDB的Table结构完全不同,它不是规整的二维矩阵形态,笔者大胆推测,应该更类似树形结构。树的子节点是可以在程序运行时任意添加的,而ColumnFamily中Column也是动态增减的。
  • 2.Cassandra对Column的组织是严格顺序结构的,很可能是类似TreeSet的有序树型结构。这也很好解释为啥ColumnFamily必须定义Column的排序规则,并且数据结构中有ColumnPath这个概念(看上去很像url路径,不是吗?)


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初体验告一段落。


  
分享到:
评论
26 楼 linliangyi2007 2010-10-16  
ferly_j 写道
最近要做一个站内发消息的功能,用户量大了数据库会很难承受(不喜欢水平拆分的方式),想试试nosql,不知道nosql是否适合这种场景,有什么风险不,希望大拿们给点意见。


目前nosql数据库已经在这个方面大量使用了,从风险上说,应该不大,就看用好用坏的问题了
25 楼 ferly_j 2010-10-16  
最近要做一个站内发消息的功能,用户量大了数据库会很难承受(不喜欢水平拆分的方式),想试试nosql,不知道nosql是否适合这种场景,有什么风险不,希望大拿们给点意见。
24 楼 forchenyun 2010-10-15  
基于Java的可以考虑voldemort
发展比较迅速,最好的是它是纯Java写的
目前的情况来看,很不错,遗憾是只基于key查询
23 楼 gh_aiyz 2010-10-15  
firebody 写道
linliangyi2007 写道
firebody 写道
MongoDB+morphia

该有的都有了。


很好的配合。

像请教楼上的大拿,是否有MongoDB+morphia的实用经历,你们是用在那一块的业务上的,能否稍微说说,给个选型的参考意见,谢谢

业务系统 做信息发布到 互联网网站上,
很简单的信息发布,以前是做静态化的发布,现在改成直接将信息发布到mongodb,互联网网站基于 mongoDB+morphia搭建。
mongodb提供的查询统计是目前nosql中最强大的,而且其mapReduce也基本能够满足聚合统计的需要。 

值得提到的是 morphia提供了 对象关联的机制,从对象的角度来看,感觉和orm差别不大。

你可以下载 morphia的源代码,看其中关于reference的实现,非常不错。

我个人认为基于关系数据库做复杂的sharding设计,还不如用 nosqldb来做这块事情。 需要重点考虑的是统计查询的设计要比关系数据库复杂得多,但是不要被这个困难吓到,到头来你发现这个上面花费的功力比要做关系数据库的sharding然后做统计查询也差不了多少去。

认同这个看法,做了sharding以后,其实已经弱关系化了。不如直接NoSQL。
22 楼 gh_aiyz 2010-10-15  
貌似digg等公司都逐渐在放弃cassandra
似乎有一定的问题
使用到生产环境需要谨慎。
21 楼 linliangyi2007 2010-10-15  
net_hare 写道
Cassandra的排序要在建表的时候就定义好。我就是被这一特性给吓住的。我的理解Cassandra必须和传统数据库配合使用才能发挥其作用。


这里的排序是这列的存放顺序,请不要跟DB的orderby 混为一谈,它相当于DB中表列名的顺序,而不是记录的顺序。
20 楼 net_hare 2010-10-15  
Cassandra的排序要在建表的时候就定义好。我就是被这一特性给吓住的。我的理解Cassandra必须和传统数据库配合使用才能发挥其作用。
19 楼 linliangyi2007 2010-10-15  
yangfuchao418 写道
linliangyi2007 写道
yangfuchao418 写道
用户动态信息用neo4j.

看来最近这类DB很多样啊,昨天某位大拿还在说MongoDB呢,花样多多啊。neo4j能用来存储空间数据吗?比如道路节点数据?!没用过,只是突发奇想的问问,呵呵!


按照数据模型保存性质将当前NoSQL分为四种:
1.Key-value stores键值存储, 保存keys+BLOBs (二进制大对象Binary Large OBjects)
2.Table-oriented 面向表, 主要有Google的BigTable和Cassandra.
3.Document-oriented面向文本, 文本是一种类似XML文档,MongoDB 和 CouchDB
4.Graph-oriented 面向图论. 如Neo4J.

所以neo4j很适合做用户动态,关系。
http://www.infoq.com/cn/news/2010/02/neo4j-10


非常感谢这样的总结,补充一个 Tokyo Tyrant, 其作为Memcached的持久化版本,应该是典型的Key-value stores键值存储
18 楼 yangfuchao418 2010-10-15  
linliangyi2007 写道
yangfuchao418 写道
用户动态信息用neo4j.

看来最近这类DB很多样啊,昨天某位大拿还在说MongoDB呢,花样多多啊。neo4j能用来存储空间数据吗?比如道路节点数据?!没用过,只是突发奇想的问问,呵呵!


按照数据模型保存性质将当前NoSQL分为四种:
1.Key-value stores键值存储, 保存keys+BLOBs (二进制大对象Binary Large OBjects)
2.Table-oriented 面向表, 主要有Google的BigTable和Cassandra.
3.Document-oriented面向文本, 文本是一种类似XML文档,MongoDB 和 CouchDB
4.Graph-oriented 面向图论. 如Neo4J.

所以neo4j很适合做用户动态,关系。
http://www.infoq.com/cn/news/2010/02/neo4j-10
17 楼 xkorey 2010-10-15  
一直在关注NOSQL DB。楼上你们的经验很不错!毕竟这类数据库刚开始出现!我提议咱们一块做个NOSQL的数据库来!怎么样?
16 楼 linliangyi2007 2010-10-14  
firebody 写道
linliangyi2007 写道
firebody 写道
MongoDB+morphia

该有的都有了。


很好的配合。

像请教楼上的大拿,是否有MongoDB+morphia的实用经历,你们是用在那一块的业务上的,能否稍微说说,给个选型的参考意见,谢谢

业务系统 做信息发布到 互联网网站上,
很简单的信息发布,以前是做静态化的发布,现在改成直接将信息发布到mongodb,互联网网站基于 mongoDB+morphia搭建。
mongodb提供的查询统计是目前nosql中最强大的,而且其mapReduce也基本能够满足聚合统计的需要。 

值得提到的是 morphia提供了 对象关联的机制,从对象的角度来看,感觉和orm差别不大。

你可以下载 morphia的源代码,看其中关于reference的实现,非常不错。

我个人认为基于关系数据库做复杂的sharding设计,还不如用 nosqldb来做这块事情。 需要重点考虑的是统计查询的设计要比关系数据库复杂得多,但是不要被这个困难吓到,到头来你发现这个上面花费的功力比要做关系数据库的sharding然后做统计查询也差不了多少去。


非常感谢fireboy ,你的意见很有价值,看来要好好研究一下了。
15 楼 firebody 2010-10-14  
linliangyi2007 写道
firebody 写道
MongoDB+morphia

该有的都有了。


很好的配合。

像请教楼上的大拿,是否有MongoDB+morphia的实用经历,你们是用在那一块的业务上的,能否稍微说说,给个选型的参考意见,谢谢

业务系统 做信息发布到 互联网网站上,
很简单的信息发布,以前是做静态化的发布,现在改成直接将信息发布到mongodb,互联网网站基于 mongoDB+morphia搭建。
mongodb提供的查询统计是目前nosql中最强大的,而且其mapReduce也基本能够满足聚合统计的需要。 

值得提到的是 morphia提供了 对象关联的机制,从对象的角度来看,感觉和orm差别不大。

你可以下载 morphia的源代码,看其中关于reference的实现,非常不错。

我个人认为基于关系数据库做复杂的sharding设计,还不如用 nosqldb来做这块事情。 需要重点考虑的是统计查询的设计要比关系数据库复杂得多,但是不要被这个困难吓到,到头来你发现这个上面花费的功力比要做关系数据库的sharding然后做统计查询也差不了多少去。
14 楼 swordice 2010-10-14  
很不错的文章,从学习Lucene开始就一直关注linliangyi2007  O(∩_∩)O~
最近使用HBase比较多,开发也是基于HDFS和HBase来实现大规模的数据存储
关于Casssandra,现在能找到的资料很少,对它的了解仅限于wiki,期待linliangyi2007更多的文章
13 楼 liuye 2010-10-14  
linliangyi2007 写道
firebody 写道
MongoDB+morphia

该有的都有了。


很好的配合。

像请教楼上的大拿,是否有MongoDB+morphia的实用经历,你们是用在那一块的业务上的,能否稍微说说,给个选型的参考意见,谢谢


我在实际项目中使用过MongoDB+morphia,感觉不错
12 楼 linliangyi2007 2010-10-14  
firebody 写道
MongoDB+morphia

该有的都有了。


很好的配合。

像请教楼上的大拿,是否有MongoDB+morphia的实用经历,你们是用在那一块的业务上的,能否稍微说说,给个选型的参考意见,谢谢
11 楼 firebody 2010-10-14  
MongoDB+morphia

该有的都有了。
10 楼 linliangyi2007 2010-10-14  
yangfuchao418 写道
用户动态信息用neo4j.

看来最近这类DB很多样啊,昨天某位大拿还在说MongoDB呢,花样多多啊。neo4j能用来存储空间数据吗?比如道路节点数据?!没用过,只是突发奇想的问问,呵呵!
9 楼 yangfuchao418 2010-10-14  
用户动态信息用neo4j.
8 楼 linliangyi2007 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使用,也是可以的,当然你就必须考虑上述的系列化中的性能问题。
7 楼 myreligion 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是新东西,总要有点新期待吧

相关推荐

Global site tag (gtag.js) - Google Analytics