在Cassandra中设置一个如下所示的表:
shard
- 介于1和1000之间的整数last_used
- 时间戳value
- 一个22个字符的字符串shard last_used | value
------------------------------------
457 5/16/2012 4:56pm NBJO3poisdjdsa4djmka8k >-- Remove from front...
600 6/17/2013 5:58pm dndiapas09eidjs9dkakah |
...(1 million more rows) |
457 NOW NBJO3poisdjdsa4djmka8k <-- ..and put in back
该表用作巨型队列。很多线程试图以最低last_used
值“弹出”该行,然后将last_used
值更新为当前时刻。这意味着,一旦读取了一行,由于last_used
是主键的一部分,该行将被删除,然后是具有相同shard
,value
和更新{{{ 1}}时间被添加到表中,位于“队列末尾”。
last_used
就在那里,因为有很多进程正在尝试shard
队列前面最老的一行并把它放在后面,如果只有一个就可以相互严重瓶颈同时访问队列。这些行随机分成1000个不同的“碎片”。每次线程从队列的开头“弹出”一行时,它会选择一个其他线程当前没有使用的分片(使用redis)。
我们遇到的问题是这个操作变得非常缓慢,大约30秒,虚拟永恒。
我们只使用Cassandra不到一个月,所以我们不确定我们在这里做错了什么。我们已经得到一些迹象表明,也许我们不应该在同一张桌子上写这么多东西。难道我们不应该在Cassandra这样做吗?或者,我们正在采取的方式或我们配置的方式可能需要改变和/或调整?怎么可能麻烦这个?
非常感谢!
答案 0 :(得分:7)
这是你不应该使用Cassandra的东西。你遇到性能问题的原因是因为Cassandra必须扫描一下墓碑山才能找到剩余的实时列。每当你删除Cassandra写一个墓碑的东西时,它就是一个标记,该列已被删除。在压缩之前,实际上没有从磁盘中删除任何内容。当压缩Cassandra看着墓碑并确定哪些列已经死亡以及哪些列仍然存在时,死亡的那些被丢弃(但是那时还有GC恩典,这意味着为了避免列的虚假复活,Cassandra会保留墓碑周围的墓碑有一段时间了。)
由于您不断添加和删除列,因此会有大量的墓碑,并且它们将分布在许多SSTable上。这意味着Cassandra必须做很多工作才能拼凑一行。
阅读blog post "Cassandra anti-patterns: queues and queue-like datasets"了解更多详情。它还向您展示了如何跟踪查询以自行验证问题。
从您的描述中并不完全清楚什么是更好的解决方案,但它听起来像RabbitMQ之类的消息队列,或者Kafka可能是一个更好的解决方案。它们具有恒定的流失和FIFO语义,而Cassandra则不然。
有一种方法可以让Cassandra的查询不那么重,你可以尝试(虽然我仍然会说Cassandra是这个工作的错误工具):如果你可以在查询中包含一个时间戳你应该打主要是活柱。例如。将last_used > ?
(其中?是时间戳)添加到查询中。这要求您大致了解第一个时间戳(并且不进行查询以找出它,这将是同样昂贵的),因此它可能对您不起作用,但它会占用一些负载卡桑德拉。
答案 1 :(得分:2)
系统似乎处于压力之下(2GB或RAM可能不够)。 请运行nodetool tpstats并报告其结果。
答案 2 :(得分:1)
使用RabbitMQ。 Cassandra可能是这个应用程序的不错选择。