楼主: jieforest

[转载] Cassandra数据模型设计最佳实践

[复制链接]
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
21#
 楼主| 发表于 2013-11-3 00:56 | 只看该作者
总结

我们通过一些基本的实践和详细例子帮你开启Cassandra数据建模之旅。下面是一些关键点:

1) 当设计Cassandra列族时,不要把它想成是关系表,要把它想成是嵌套的、排序的map数据结构。

2) 要围绕着查询来设计列族,从设计实体及其关系开始。

3) 在需要的时候,通过反范式化和冗余来提升读性能。

4) 记住有多种方式创建模型,最佳的方式依赖于你的用例和查询模式。

这里我没有提到其它常用的用例,如日志记录、监控、实时分析(rollups, counters),或者时间序列。但是,我们讨论的实践也适用于它们。此外,有些众所周知的技术和模式用于时间序列的模型设计。在eBay,我们也使用这些技术,也乐于在后续的文章中分享这些。关于时间序列数据建模,我推荐你阅读 Advanced time series with Cassandra 和 Metric collection and storage,如果你是Cassandra新手,请先阅读DataStax documentation。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
22#
 楼主| 发表于 2013-11-3 00:56 | 只看该作者

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
23#
 楼主| 发表于 2013-11-3 00:57 | 只看该作者
在第一部分中,我们介绍了一些基本实践,然后通过一个具体的例子帮助大家开启Cassandra数据模型设计之旅。你可以跳过第一部分直接阅读本篇文章,但是我推荐你看看第一篇文章中“术语和约定”部分。如果你是一个Cassandra新手,我还是建议你先阅读第一部分。

以下列出的实践有些可能会发生变化,我将提供相关JIRA地址给大家,以方便跟踪最新进展。下面让我们先从几个基本实践开始吧!

通过column name存储数据是完全OK的

同样让colunmn value为空也是没问题的

通过column name存储数据是一项常用的实践,同样如果没有必要保存column value,你也可以让它为空。这样做的动机是column name是物理有序存储的的,而column value不是。(译者注:比如某个column name为字符串类型,那么插入005、001、003、007最终的存储顺序将是001、003、005、007,这将意味着可以根据column name顺序读取数据)。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
24#
 楼主| 发表于 2013-11-7 10:27 | 只看该作者
注意:

column name(以及row key)最大为64KB,所以请不要存储如“物品描述”之类的信息。

不要单独使用timestamp作为column name,那样会导致2个或者多个应用服务器同时写入Cassandra时造成数据覆盖(译者注:相同row key,相同column name会覆盖column value),推荐使用uuid(type-1 uuid)代替(译者注:time-based UUID主要由cassandra客户端时间戳、序列号、MAC地址组成,这样的组合可以大大降低数据冲突)。

column value最大为2GB,它的采用非流式数据读取,cassandra会将整个value加载到heap内存中,这是很危险的,所以请确保column value只存储不超过几MB的数据。(使用column value进行大数据存储一段时间内都不会被支持,参见 Cassandra-265,但是通过Cassandra java 客户端——Astyanax,可以通过分块的方式解决这个问题)。

使用宽行(wide row)进行排序、分组和过滤

但不要搞的太长

这个实践与上面的内容相关,当实际数据通过column name存储,我们会考虑使用宽行。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
25#
 楼主| 发表于 2013-11-7 10:29 | 只看该作者
宽行的好处:

1)因为column name是物理有序存储的,所以宽行对于排序和高效过滤(范围查找)有优势,而且如果需要,你仍然可以高效查找宽行中单独的column。

2)如果一次要查询多个数据,你可以将数据分组然后保存到一个宽行中,如此可以快速读取数据。举个例子,跟踪和监控一些时间序列数据,我们可以通过“小时/日期/机器/事件”将数据分组到一个wide row,每个column包含刻度数据或者累加数据。我们也可以使用Super Column或者Composite Column进一步分组数据到一个row中,这个我们后面会讨论。

3)在Cassandra中,宽行column family常常与composite column一起配合用于构建自定义索引。

4)这里还有个额外的好处,如果你希望数据被一同查出或者优化读性能,你可以通过反范式化(de-normalize)one-to-many关系模型来实现这个功能。(译者注:还记得第一篇文章中的示例吗?一个User喜爱多个Item,一个User就是一个row key,column为多个Item)

示例:

假设我们系统存储一些事件日志数据,然后按照小时获取它们。请看下面的模型,row key是日期和小时,column name存储事件发生的时间,column value保存负荷值(payload)。请注意,这是一个宽行,事件通过时间顺序进行存储。宽行的间隔刻度(当前示例中,小时刻度比分钟更适合)由实际用例、流量和数据大小决定,我们马上会讨论到它们。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
26#
 楼主| 发表于 2013-11-7 10:29 | 只看该作者
即使是宽行也不要太宽,因为一个row的数据不会跨节点保存

很难准确的说一个宽行多少个column才合适,这依赖于你的用例,下面是一些建议:

流量:所有流量相关数据保存到一个row中将导致只有一个节点能够提供服务(假设只有一个数据副本)。那样的row太庞大,当row的数量小于集群节点数(希望这不会发生),或者宽行与窄行(skinny row)混合使用,再或者一些行访问更频繁,都可能出现集群热点问题。但是,集群负载均衡最终依靠rowkey选择;相反地,rowkey也决定row的长度。所以在设计模型的时候要谨记负载均衡。

大小:因为row不会跨节点分割,所以单个row必须适应节点磁盘大小。但是,row可以拥有大量column,因为它不会加载到内存。Cassandra允许每个row包含20亿个column。在ebay,我们没有做任何宽行测试,我们从不保存超过百万column或者MB大小数据到单个row(我们改变rowkey刻度或者分割为多个row)。如果你有兴趣,可以看看Aaron Morton关于宽行性能的文章—— 《Cassandra Query Plans》(译者注:原文链接404)。

但是,这些建议不意味你不应该使用宽行,只是不要搞的太长就好。

译者注:原文Cassandra-4176和Cassandra-3929,这两个bug的状态为永不修复,这里就不翻译了。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
27#
 楼主| 发表于 2013-11-7 10:30 | 只看该作者
选择合适的rowkey

否则,你将死于热点,即使你使用 RandomPartitioner

让我们再次考虑上面的示例,存储时间序列日志,同时按小时获取它们。我们使用日期小时作为rowkey以保证一小时数据在一个row里。但是,这里有个问题,当前时间的所有写入都集中到一个节点将导致热点问题。减少rowkey刻度从小时到分钟并不能真正解决问题,因为1分钟内的数据仍然只会写入一个节点。随着时间推移,热点会移到其他节点但不会消失!

糟糕的 row key: “ddmmyyhh”

一种减轻问题的方式是添加一些信息到rowkey——事件类型、机器ID,或者适应你用例的类似值。

不错的 row key: “ddmmyyhh|eventtype”

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
28#
 楼主| 发表于 2013-11-7 10:31 | 只看该作者
选择合适的rowkey

否则,你将死于热点,即使你使用RandomPartitioner

让我们再次考虑上面的示例,存储时间序列日志,同时按小时获取它们。我们使用日期小时作为rowkey以保证一小时数据在一个row里。但是,这里有个问题,当前时间的所有写入都集中到一个节点将导致热点问题。减少rowkey刻度从小时到分钟并不能真正解决问题,因为1分钟内的数据仍然只会写入一个节点。随着时间推移,热点会移到其他节点但不会消失!

糟糕的 row key: “ddmmyyhh”

一种减轻问题的方式是添加一些信息到rowkey——事件类型、机器ID,或者适应你用例的类似值。

不错的 row key: “ddmmyyhh|eventtype”

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
29#
 楼主| 发表于 2013-11-7 10:31 | 只看该作者
注意,在这个column family中,我们现在没有对所有事件按全局时间进行排序,如果我们是通过事件类型来查询数据的话,这将不是问题,如果用例要求按照时间顺序获取所有事件,我们就需要使用multi-get方法一次查询多个event rowkey,然后将数据在Cassandra客户端程序中将数据按照时间顺序合并即可。

如果你不能添加任何信息到rowkey或者的确需要时间周期作为rowkey,另一个选择是将你的row key手工分割为:“ddmmyyhh | 1″, “ddmmyyhh | 2″,… “ddmmyyhh | n”, N值为集群的节点数。一小时内,可以用轮询的方式写入各个节点。当读取数据的时候,你需要使用multi-gets方法获取所有节点的数据并做合并。(假设这里使用RandomPartitioner,因此无法使用rowkey范围查询)

让读多数据与写多数据分离

这么做,你能够充分利用Cassandra的off-heap行缓存特性。(译者注:off-heap是一种脱离java gc的用法,通过api可以直接分配、释放内存)

无论NOSQL与否,保持读写数据分离都是一个不错的实践。

注意:行缓存对于窄行来说很有用,但对宽行却无益,因为它会将整个行数据放到内存中。通过Cassandra-1956 和 Cassandra-2864 未来可能改变这一现象,但是保持读写分离这项实践将仍然适用。

假如你的column family有大量数据(超过可用内存),同时有热行,开启行缓存可能对你有用。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
30#
 楼主| 发表于 2013-11-7 10:32 | 只看该作者
确保column key和row key是唯一的

否则,数据可能被覆盖

在Cassandra(一个分布式数据库)中,row key和 column key是没有强制唯一性约束的。

同样地,cassandra也没有update操作。cassandra所有操作都是upsert(不存在插入,存在则更新)操作。如果你插入的数据之前已经存在相同row key和column key,那么之前的column value将会被悄无声息地覆盖(cassandra column value是没有版本的,之前的数据将无法找回)。

使用合适的 comparator 和validator

除非你真的需要,否则不要使用默认的BytesType comparator 和 validator

在Cassandra中,column value(或者row key)的数据类型称为“Validator”。一个column name的数据类型称为“Comparator”。虽然Cassandra不要求你全部定义它们,但你必须至少指定comparator,除非你的column family是静态的(就是说,你不会存储实际的数据作为column name的一部分),或者你真的不关心column排序。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表