6

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

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

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

有一篇关于 datastax的文章描述了陷阱以及如何绕过它,但是我不确定周围有很多墓碑的影响是什么,它们会停留多长时间?

4

3 回答 3

20

不要这样做。除非您非常非常小心,否则 Cassandra 作为队列后端是一个糟糕的选择。您可以在Jonathan Ellis 博客文章“Cassandra 反模式:队列和类似队列的数据集”(这可能是您所暗示的帖子)中阅读更多原因。MySQL 也不是支持队列的好选择,我们是像 RabbitMQ 这样的真正队列产品,它很棒而且非常易于使用。

使用 Cassandra 作为队列存储的问题是:每次删除消息时,都会为该消息编写墓碑。每次您查询下一条消息时,Cassandra 都必须遍历那些墓碑和已删除的消息,并尝试确定少数未被删除的消息。对于任何类型的吞吐量,读取值的数量与实际实时消息的数量将是数十万比一。

调整 GC 宽限和其他参数将无济于事,因为这仅适用于压缩后墓碑会挂起多长时间,即使您将 CPU 专用于仅运行压缩,您仍然会有数万或更多的死活口粮. 在某些情况下,即使 GC 优雅为零墓碑也会在压缩后徘徊。

有一些方法可以减轻这些影响,它们在 Jonathan 的帖子中进行了概述,但这里有一个总结(我写这篇文章并不是为了鼓励你使用 Cassandra 作为队列后端,而是因为它解释了更多关于 Cassandra 工作的信息,并且应该可以帮助您理解为什么它不适合该问题):

为了避免墓碑问题,你不能继续使用相同的队列,因为它会比压缩更快地填满墓碑,并且你的性能将直接陷入困境。如果您向主键添加一个确定性且取决于时间的列,您可以避免一些性能问题,因为更少的 tombstone 有时间建立,并且 Cassandra 将能够完全删除旧行及其所有 tombstone。

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

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

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

StackOverflow 上还有一些关于 Cassandra 和队列的答案,请阅读它们(从以下内容开始:Table with heavy writes and some reads in Cassandra。主键搜索需要 30 秒

于 2013-07-30T15:24:37.487 回答
2

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

gc_grace_seconds¶

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

取自 文档

另一方面,我认为在 Cassandra 中实现队列模式并不是很有用。为了防止您的工作人员两次处理一个条目,您需要强制执行“ALL”读取一致性,这违背了分布式数据库系统的目的。我强烈建议查看专门的系统,例如原生支持队列模式的消息传递系统。以RabbitMQ为例。您将立即启动并运行。

于 2013-07-30T12:14:50.317 回答
0

Theo 关于不使用 Cassandra 进行队列的回答是正确的。

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

于 2013-12-06T13:30:02.993 回答