是否可以使用cassandra表作为基本队列

时间:2013-07-30 11:33:26

标签: queue cassandra cql cql3

是否可以将cassandra中的表用作队列,我不认为我在mysql中使用的策略有效,即给出此表:

create table message_queue(id integer, message varchar(4000), retries int, sending boolean);

我们有一个事务将该行标记为“发送”,尝试发送,然后删除该行,或递增重试次数。该事务确保在任何时候只有一个服务器将尝试从message_queue处理项目。

有一篇文章on datastax描述了陷阱以及如何解决它,但是我不确定周围有很多墓碑的影响是什么,它们需要多长时间?

3 个答案:

答案 0 :(得分:17)

不要这样做。除非你非常非常小心,否则Cassandra作为队列后端是一个糟糕的选择。您可以在Jonathan Ellis blog post "Cassandra anti-patterns: Queues and queue-like datasets"中阅读更多原因(可能是您提到的帖子)。 MySQL也不是支持队列的绝佳选择,我们是像RabbitMQ这样的真正的队列产品,它很棒且非常易于使用。

使用Cassandra作为队列存储的问题是:每次删除消息时,都要为该消息编写逻辑删除。每当您查询下一条消息时,Cassandra将不得不浏览这些墓碑并删除消息并尝试确定少数尚未删除的消息。对于任何类型的吞吐量,读取值的数量与实际实时消息的数量将是数十万比一。

调整GC宽限和其他参数将无济于事,因为这仅适用于在压缩后墓碑会停留多长时间,即使你专注于CPU只运行压缩,你仍然会死去几十年的口粮成千上万。即使GC的恩典为0,在某些情况下,压缩之后会出现墓碑。

有一些方法可以缓解这些影响,Jonathan的帖子中概述了这些影响,但这里有一个摘要(我不会写这个来鼓励你使用Cassandra作为队列后端,但是因为它解释了更多关于Cassandra有效,应该可以帮助你理解为什么它不适合这个问题):

为了避免墓碑问题,你不能继续使用相同的队列,因为它会比使用更快的方式填充墓碑更快,而且你的性能会直接进入砖墙。如果您向主键添加一个确定性且依赖于时间的列可以避免一些性能问题,因为较少的逻辑删除有时间构建,Cassandra将能够完全删除旧行及其所有逻辑删除。

每个队列使用一行也会创建一个热点。单个节点必须处理该队列,其余节点将处于空闲状态。你可能有很多队列,但很有可能其中一个会看到比其他队列更多的流量,这意味着你得到一个热点。通过向主键添加第二列,在多个节点上对队列进行分片。它可以是消息的哈希值(例如crc32(message) % 60将创建60个分片,不要使用太小的数字)。当您想要查找从所有分片中读取的下一条消息并选择其中一条结果时,忽略其他分片。理想情况下,你会找到一种方法将这种方法与依赖于时间的东西结合起来,这样你就可以解决这个问题。

如果您在到达时间之后对消息进行排序(例如使用TIMEUUID群集密钥)并且可以以某种方式跟踪已传递的最新消息,则可以执行查询以查找该消息之后的所有消息。这意味着Cassandra的墓碑会越来越少,但它不是灵丹妙药。

然后是确认问题。我不确定它们是否对您很重要,但看起来您的架构中有某种锁定机制(我正在考虑retriessending列)。这不行。在Cassandra 2.0及其比较和交换功能之前,没有办法使其正常工作。要实现锁定,您需要读取列的值,检查它是否未锁定,然后写入它现在应该被锁定。即使是一致性级别ALL,另一个应用程序节点也可以同时执行相同的操作,并且最终都认为它们锁定了消息。使用CAS在Cassandra 2.0中,可以原子地进行,但是以性能为代价。

StackOverflow上有关于Cassandra和队列的更多答案,请阅读它们(从这开始:Table with heavy writes and some reads in Cassandra. Primary key searches taking 30 seconds

答案 1 :(得分:2)

可以定义宽限期。默认情况下,它是10天:

  

gc_grace_seconds¶

     

(默认值:864000 [10天])指定垃圾之前等待的时间   收集墓碑(删除标记)。默认值允许a   在删除之前要实现一致性的大量时间。   在许多部署中,可以减少此间隔,并在单节点中   集群可以安全地设置为零。使用CLI时,请使用gc_grace   而不是gc_grace_seconds。

取自 documentation

另一方面,我不认为在Cassandra中实现队列模式非常有用。为了防止您的工作程序两次处理一个条目,您需要强制执行“ALL”读取一致性,这会破坏分布式数据库系统的用途。 我强烈建议您查看专门的系统,例如本机支持队列模式的消息系统。例如,查看RabbitMQ。您将立即启动并运行。

答案 2 :(得分:0)

Theo关于不使用Cassandra进行排队的答案很明显。

只是想补充一点,我们一直在为我们的队列使用Redis排序集,并且它一直运行良好。我们的一些队列有数千万个元素,每秒访问数百次。