什么是deviseCassandra数据模型的最佳实践?

有什么要避免的陷阱? 你有什么交易吗? 例如,我听说导出/导入Cassandra数据非常困难,这让我想知道是否会妨碍将生产数据同步到开发环境。

顺便说一句,在Cassandra上find很好的教程是非常困难的,我唯一拥有的http://arin.me/code/wtf-is-a-supercolumn-cassandra-data-model仍然是非常基础的。

谢谢。

对我来说,最主要的是决定是否使用OrderedPartitioner或RandomPartitioner。

如果使用RandomPartitioner,范围扫描是不可能的。 这意味着你必须知道任何活动的确切关键,包括清理旧数据。

所以,如果你有很多的stream失,除非你有一些神奇的方式来确切地知道你已经插入的东西,使用随机分区你可以很容易地“丢失”的东西,这会导致磁盘空间泄漏,并最终消耗所有存储。

另一方面,你可以问有序的分区器“我在A和B之间的列族X中有什么键”? – 它会告诉你的。 你可以清理它们。

然而,也有一个缺点。 由于Cassandra不会自动进行负载均衡,所以如果使用有序分区器,所有数据很可能最终只会在一个或两个节点中,而其他所有数据都不会,这意味着您将浪费资源。

我没有任何简单的答案,除非你在某些情况下可以通过在你的密钥的开头加上一个简短的散列值(你可以很容易地从其他数据源中枚举的东西)获得“两全其美”例如用户ID的16位hex散列 – 它会给你4个hex数字,然后是你真正想使用的密钥。

那么如果你有一个最近删除的用户列表,你可以散列他们的ID和范围扫描清理任何相关的东西。

下一个棘手的问题是辅助索引 – Cassandra没有 – 所以如果你需要用Y查找X,你需要在两个键下面插入数据,或者有一个指针。 同样,这些指针可能需要清理,当他们指向的东西不存在,但没有简单的方法在这个基础上查询的东西,所以你的应用程序只需要记住。

应用程序错误可能会遗留已遗忘的孤立键,除非您编写一些定期扫描db中每个键的垃圾回收器,否则您将无法轻松检测到它们(这将需要一段时间 – 但你可以做大块)来检查那些不再需要的。

这些都不是基于真实的用法,而是我在研究过程中发现的。 我们不在生产中使用Cassandra。

编辑:Cassandra现在在主干中有二级索引。

为了澄清问题列表中的一些错误概念,

  1. 任何客户端都可以连接到任何节点; 如果您select的第一个节点(或通过负载平衡器连接到的节点)发生故障,只需连接到另一个节点即可。 另外,一个“胖客户端”api可用于客户可以指导自己的写操作; 一个例子是http://wiki.apache.org/cassandra/ClientExamples

  2. 当服务器没有响应,而不是无限期地挂起时,定时出问题的是大多数处理重载rdbms系统的人所希望的。 Cassandra RPC超时是可configuration的; 如果你愿意的话,你可以自由地将它设置为几天,而无限期地处理挂起。 🙂

  3. 确实没有多重删除或截断的支持,但是这两个都有补丁。

  4. 在群集节点间保持负载平衡显然是一个折衷:你试图保持的东西越平衡,你将做的数据移动越多,这是不自由的。 默认情况下,Cassandra集群中的新节点将移动到令牌环中的最佳位置,以最小化不均匀性。 在实践中,这已被certificate是行之有效的,而且你的集群越大,加倍是最佳的也就越less。 这在http://wiki.apache.org/cassandra/Operations中有更多的介绍;

你有没有什么交易? 不一定要处理破坏者,但需要注意的事情

  1. 一个客户端连接到一个最近的节点,这个节点应该事先知道它与所有其他Cassandra节点通过它进行代理的通信。 一个。 读/写stream量不是均匀分布在节点之间的 – 一些节点比它们自己托pipe更多的数据。 如果节点出现故障,客户端无奈,无法读取,无法写入集群中的任何地方。

  2. 尽pipeCassandra声称“写作永远不会失败”,但他们确实失败了,至less在发言的那一刻他们确实失败了。 如果目标数据节点变得缓慢,请求超时和写入失败。 节点没有响应的原因有很多:垃圾收集器踢,压缩过程,无论什么…在所有这样的情况下,所有的写/读请求失败。 在传统的数据库中,这些请求会变得相当缓慢,但是在卡桑德拉他们只是失败了。

  3. 有多重获取,但没有多重删除,也不能截断ColumnFamily

  4. 如果一个新的空数据节点进入集群,那么来自密钥环上的一个相邻节点的数据的一部分将仅被传送。 这导致数据分布不均匀和负载不均匀。 你可以通过总是加倍节点来修复它。一个人也应该手动跟踪令牌并明智地select它们。

另一个教程是在这里: http : //blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/ 。

自从Cassandra 1.2最近出来以后,我认为这是值得一提的。

在过去的18个月里,我一直在使用Cassandra进行社交游戏。

我的意思是,你必须使用Cassandra的优势。 因此,了解它是什么以及如何进行的,有必要查看使用哪种数据模型,甚至确定另一个数据库解决scheme是否对您更有用。

OrderedPartitioner仅在您的应用程序依赖关键字范围查询时才有用,但是您放弃了Cassandra最强大的function之一:自动分片和负载平衡。 而不是行键范围查询尝试实现相同的function,你需要使用同一行内的列名称范围。 TL; DR读取/写入将不会在使用此节点的节点之间进行平衡。

如果你想支持大数据和高访问频率, RandomPartioner (md5哈希)和MurmurPartitioner (Murmur哈希,更好更快)就是你必须去的方式。 你放弃的唯一的关键是范围查询。 同一行中的所有内容仍位于集群中的同一节点上,您可以在这些节点上使用比较器和列名称范围查询。 TL; DR :把这个用于正确的平衡,你不会放弃任何重大的事情。


你应该知道的关于cassandra的东西:

Cassandra是EVENTUALLY一致的。 卡桑德拉已经select交易一致性的高可用性和优秀的分区( http://en.wikipedia.org/wiki/CAP_theorem )。 但是你可以从cassandra获得一致性,当你读写它的时候就是一致的策略。 在讨论使用cassandra时,这是一个相当重要和复杂的主题,但您可以在http://www.datastax.com/docs/1.2/dml/data_consistency上详细了解它。;

作为一个经验法则(并保持简单),我在QUORUM ConsistencyLevel中读写(因为在我的应用程序中,读取的频率往往与写入次数相同)。 如果您的应用程序非常繁重,阅读发生的次数less得多,那么可以在ONE处使用写入,然后在ALL处阅读。 或者如果你的用例是相反的(写入比读取频率less得多),那么你可以尝试阅读一个,并写在所有。 使用ANY作为写入的一致性级别不是一个好主意,如果一致性是你正在试图解决的,因为它保证突变已经到达集群,但不是它已经写在任何地方。 这是我得到写入的唯一情况,在cassandra上默默无闻。

这些简单的规则使得cassandra开发变得容易。 为了从生产集群中获得尽可能多的一致性和性能,您应该深入研究这个主题,并且自己真正理解它。

如果你需要一个具有复杂关系的实体(表)的人类可读的数据模型,那么我不认为卡桑德拉是给你的。 MySQL和NewSQL可能对你的用例更有帮助。

要知道的一个好消息大概是cassandra如何保存和读取数据。 无论何时写入(删除实际上是在cassandra中写入“墓碑”值),系统都会将新值和时间戳放在新的物理位置。

当你读到的时候,cassandra试图把某个key / column_name位置的所有写操作都返回给你,并返回他能find的最近的一个(客户端给出的时间戳最高的那个)。 所以节点所需的内存直接取决于写入的频率。 cassandra有一个压缩过程,负责清理旧的突变。 Cassandra有一个内部caching,在读取时更新位置的最新值。

SSTables的磁盘上的合并/压缩(持久数据的数据结构)可以被读取引起,但最好不要指望它。 墓碑和过期列的清理(使用生存时间function)是由垃圾收集器pipe理的不同机制(有关更多详细信息,请参阅GC宽限时间设置)。


这使我想到了最后一点:确保您的写入和读取将在您的群集中保持平衡!

假设您的所有用户都需要经常更新一个位置。
不要将这个理论上的单一位置映射到只有一个行键! 这将使您的所有写入仅落在群集中的一个节点上。 如果它不能带来一切(因为你有rockstar系统),至less会严重削弱集群的性能。
我的build议是用足够的不同的行密钥来存储写入,以便将您的写入分散到群集中的所有节点上。 要检索单个理论位置的所有数据,请在所有“子行键”上使用multi_get。

例如:
我想有一个所有活动的http会话(其中有uuid分配给他们)的列表。 不要全部保存到一个“会话”行键。 我用作6个节点的cassandra集群的行键是:_sessions。 然后我有一个小16键multi_get来检索所有活动的会话,或者我仍然可以通过仅使用一个简单的get(如果我知道它的uuid当然)来告诉会话是否是活动的。 如果你的集群比较大,你可能需要使用散列函数来生成分组密钥。