为什么我们需要在像PostgreSQL这样的数据库上需要像RabbitMQ这样的消息代理?


214

我是RabbitMQ之类的消息代理的新手,我们可以使用它们为Celery这样的调度系统创建任务/消息队列。

现在,这是一个问题:

  • 我可以在PostgreSQL中创建一个表,该表可以附加新任务,并由用户程序(如Celery)使用。

  • 为什么在地球上我想为此设置一种全新技术,例如RabbitMQ?

现在,我相信扩展无法解决问题,因为像PostgreSQL这样的数据库可以在分布式环境中工作。

我搜索了数据库针对特定问题带来的问题,然后发现:

  • 轮询使数据库繁忙且性能低下
  • 锁定表->再次表现不佳
  • 数百万行的任务->再次,轮询性能低下

现在,RabbitMQ或类似的任何其他消息代理如何解决这些问题?

另外,我发现该AMQP协议是遵循的。那有什么好呢?

可以Redis的也可以用作消息代理?我发现它比RabbitMQ更类似于Memcached。

请对此有所说明!


9
PostgreSQL对锁定的影响应该小得多,因为它实现了MVCC,在这种情况下,读者不会被编写者阻止,反之亦然。我发现大多数文章批评使用数据库,因为消息队列考虑了MySQL。
CadentOrange 2014年

消息代理在节点之间移动数据,而数据库将数据保留在一个位置。从表面上看,您可以从多个节点访问数据库中的数据这一事实并不能使其成为在节点之间快速传输数据的好工具。
Mayer

2
“像这样的计划系统celery”-我刚刚从问题中学到了一些对我的设计有用的东西。现在阅读答案...
Mark K Cowan

使用消息代理的生产者和消费者是分离的。
giorgi dvalishvili

您可以查看以下链接。它具有广泛的描述:stackoverflow.com/a/51377756/3073945
Sajedul Karim博士

Answers:


110

Rabbit的队列驻留在内存中,因此比在数据库中实现它要快得多。一个(好的)专用消息队列还应该提供与队列相关的基本功能,例如节流/流控制,以及选择不同路由算法的能力,以命名一对(兔子提供了这些以及更多)。根据项目的大小,您可能还希望将消息传递组件与数据库分开,这样,如果一个组件承受沉重的负担,则不必阻碍另一个组件的操作。

至于你提到的问题:

  • 轮询使数据库忙碌且性能低下:使用Rabbitmq,生产者可以更新送给消费者,这比轮询性能要好得多。只需在需要时将数据发送给消费者,从而无需进行浪费的检查。

  • 表锁定->再一次表现不佳:没有表可锁定:P

  • 数百万行的任务->再次轮询性能低下:如上所述,Rabbitmq驻留在RAM上将运行得更快,并提供流控制。如果需要,它还可以使用磁盘来临时存储消息(如果RAM不足)。在2.0之后,Rabbit的RAM使用率有了显着提高。群集选项也可用。

关于AMQP,我想说一个非常酷的功能是“交换”,以及它路由到其他交易所的能力。这为您提供了更大的灵活性,并使您能够创建各种精心设计的路由类型,这些扩展类型在扩展时非常有用。例如,请参见:


(来源:springsource.com

和:http//blog.springsource.org/2011/04/01/routing-topologies-for-performance-and-scalability-with-rabbitmq/

最后,关于redis,是的,它可以用作消息代理,并且可以做得很好。但是,Rabbitmq具有比redis更多的消息排队功能,因为Rabbitmq是从头开始构建的,是功能全面的企业级专用消息队列。另一方面,Redis最初主要是创建为内存中的键值存储(尽管它的功能远不止现在;它甚至被称为瑞士军刀)。尽管如此,我已经阅读/听说过很多人使用Redis在较小的项目上取得了不错的效果,但是在大型应用程序中却没有听到太多有关它的信息。

以下是在长时间轮询的聊天实现中使用redis的示例:http : //eflorenzano.com/blog/2011/02/16/technology-behind-convore/


2
我已经在数据库之上实现了JMS实现(即消息传递系统)。我可以告诉您,这可能的,但是这并不有趣,而且通常也没有回报。您提到的一些问题可以解决,但是确实增加了很多复杂性。总之,我同意:如果需要,请使用专用的MQ系统。但是,对于低工作负载,您可以将其保存在数据库中。
约阿希姆·绍尔

1
您只需解决所有问题/疑虑。很棒的答案!
Yugal Jindle

那很有意思。一致性又如何呢?如果队列中有数百个作业,而将其保存在ram崩溃的节点上怎么办?
Mahn 2012年

22
实际上,对于PostgreSQL,没有轮询(请参见NOTIFY),也没有表锁(请参见MVCC)。尽管PostgreSQL仍然不是为消息排队而设计的,但是它并不是完全不合适的。
jkj 2012年

3
就像@jkj所说的一样,没有NOTIFY并且没有表锁。唯一的问题似乎是消息的高带宽。您是否可以拥有专用的PostgreSQL实例,而不是维护像Rabbit这样的全新系统?您可以1)使用单个PostgreSQL实例直到遇到瓶颈,然后2)使用专用的Postgres,最后3)轻松切换为Rabbit作为代理。似乎从Rabbit开始是预先优化的。
2013年

71

PostgreSQL 9.5

PostgreSQL 9.5包含SELECT ... FOR UPDATE ... SKIP LOCKED。这使得执行工作的排队系统中很多简单和容易。您可能不再需要外部排队系统,因为现在很容易获取没有其他会话已锁定的“ n”行,并将它们保持锁定状态,直到确认完成工作为止。当需要外部协调时,它甚至可以用于两阶段事务。

外部排队系统仍然有用,可以提供固定功能,经过验证的性能,与其他系统的集成,用于水平缩放和联合的选项等。尽管如此,在简单的情况下,您实际上不再需要它们。

旧版本

不需要这样的工具,但是使用一个工具可以使生活更轻松。在数据库中进行排队看起来很容易,但是在实践中您会发现,在关系数据库中很难真正实现高性能,可靠的并发排队。

这就是为什么存在PGQ之类的工具的原因。

您可以使用LISTEN和摆脱PostgreSQL中的轮询NOTIFY,但这不会解决可靠地将队列顶部的条目可靠地分发给一个使用者的问题,同时保留高度并发的操作并且不阻塞插入。您认为可以解决该问题的所有简单明了的解决方案实际上都不是现实世界中的解决方案,并且往往会退化为效率较低的单工队列获取版本。

如果您不需要高度并发的多工作者队列获取,那么在PostgreSQL中使用单个队列表是完全合理的。


11
这行reliably handing out entries off the top of the queue to exactly one consumer while preserving highly concurrent operation and not blocking inserts. 总结了-对吗?
Yugal Jindle 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.