不要这样做。 Cassandra 作为队列后端是一个糟糕的选择,除非你非常非常小心。您可以在Jonathan Ellis blog post "Cassandra anti-patterns: Queues and queue-like datasets" 中阅读更多原因(这可能是您所暗示的帖子)。 MySQL 也不是支持队列的好选择,我们是像 RabbitMQ 这样的真正队列产品,它很棒而且非常易于使用。
使用 Cassandra 作为队列存储的问题在于:每次删除消息时,都会为该消息编写墓碑。每次您查询下一条消息时,Cassandra 都必须遍历这些墓碑和已删除的消息,并尝试确定少数未被删除的消息。对于任何类型的吞吐量,读取值的数量与实际实时消息的数量将是数十万比一。
调整 GC 宽限和其他参数将无济于事,因为这仅适用于墓碑在压缩后会挂起多长时间,即使您将 CPU 专用于仅运行压缩,您仍然会有数十个死活口粮数千或更多。在某些情况下,即使 GC 优雅为零墓碑也会在压缩后徘徊。
有一些方法可以减轻这些影响,它们在 Jonathan 的帖子中进行了概述,但这里有一个摘要(我写这篇文章并不是为了鼓励您使用 Cassandra 作为队列后端,而是因为它解释了更多关于Cassandra 有效,应该可以帮助您理解为什么它不适合该问题):
为避免墓碑问题,您不能继续使用相同的队列,因为它会比压缩消除它们的速度更快地填满墓碑,并且您的性能将直接陷入困境。如果您向主键添加一个确定性且取决于时间的列,您可以避免一些性能问题,因为更少的 tombstone 有时间建立,并且 Cassandra 将能够完全删除旧行及其所有 tombstone。
对每个队列使用单行也会创建一个热点。单个节点必须处理该队列,其余节点将处于空闲状态。您可能有很多队列,但其中一个可能会比其他人看到更多的流量,这意味着您获得了一个热点。通过向主键添加第二列,将队列分片到多个节点上。它可以是消息的哈希值(例如crc32(message) % 60 将创建 60 个分片,不要使用太小的数字)。当您想查找从所有分片中读取的下一条消息并选择其中一个结果时,忽略其他结果。理想情况下,您可以找到一种将其与依赖时间的东西结合起来的方法,这样您就可以在解决该问题的同时解决该问题。
如果您在到达时间之后对消息进行排序(例如使用TIMEUUID 集群键)并且可以以某种方式跟踪已传递的最新消息,则可以执行查询以查找该消息之后的所有消息。这将意味着更少为 Cassandra 翻墓碑,但这不是灵丹妙药。
然后是确认问题。我不确定它们对您是否重要,但看起来您的架构中有某种锁定机制(我正在考虑 retries 和 sending 列)。这行不通。在 Cassandra 2.0 和它的比较和交换功能之前,没有办法让它正常工作。要实现锁定,您需要读取列的值,检查它是否没有被锁定,然后写下它现在应该被锁定。即使具有一致性级别ALL,另一个应用程序节点也可以同时执行相同的操作,并且最终都认为他们锁定了消息。使用 Cassandra 2.0 中的 CAS,可以原子地执行操作,但会以性能为代价。
StackOverflow 上有更多关于 Cassandra 和队列的答案,请阅读它们(从以下内容开始:Table with heavy writes and some reads in Cassandra. Primary key searches taking 30 seconds。