【问题标题】:Publish/Subscribe reliable messaging: Redis VS RabbitMQ发布/订阅可靠消息:Redis VS RabbitMQ
【发布时间】:2017-10-02 08:00:24
【问题描述】:

背景

我正在制作一个发布/订阅典型应用程序,其中发布者向消费者发送消息。

发布者和消费者位于不同的机器上,它们之间的连接有时会中断。

目标

这里的目标是确保无论连接或机器本身发生什么变化,发布者发送的消息始终消费者接收>。

消息的顺序不是必须的。

问题

根据我的研究,RabbitMQ 是这个场景的正确选择:

然而,尽管 RabbitMQ 有一个关于 publish and subscriber 的教程,但本教程没有向我们介绍持久队列,也没有提到 confirms,我认为这是确保消息传递的关键。

另一方面,Redis 也可以做到这一点:

但我找不到任何官方教程或示例,我目前的轻描淡写让我相信持久队列和消息确认必须由我们完成,因为 Redis 主要是内存数据存储而不是消息代理兔MQ。

问题

  1. 对于这个用例,哪种解决方案最容易实施? (Redis 方案还是 RabbitMQ 方案?)
  2. 请提供您认为最好的示例的链接!

【问题讨论】:

    标签: javascript node.js redis rabbitmq publish-subscribe


    【解决方案1】:

    背景

    我最初想要发布和订阅消息和队列持久性。

    这在理论上,并不完全适合发布和订阅:

    • 此模式不关心是否收到消息。发布者只是扇出消息,如果有任何订阅者在听,很好,否则它不在乎。

    确实,考虑到我的需求,我需要更多的工作队列模式,甚至是 RPC 模式。

    分析

    人们说两者都应该很容易,但这确实是主观的。

    RabbitMQ 总体上有更好的官方文档,大多数语言都有清晰的示例,而 Redis 信息主要在第三方博客和稀疏的 github 存储库中——这使得它很难找到。

    至于例子,RabbitMQ 有两个例子清楚地回答了我的问题:

    通过混合这两者,我能够让发布者向多个消费者发送可靠消息——即使其中一个失败。消息不会丢失,也不会被遗忘。

    rabbitMQ 的垮台:

    • 这种方法最大的问题是,如果一个消费者/工作者崩溃,你需要自己定义逻辑以确保任务不会丢失。发生这种情况是因为一旦任务完成,遵循来自工作队列的持久队列的 RPC 模式,服务器将继续向工作人员发送消息,直到它再次恢复。但是worker不知道它是否已经从服务器读取了回复,所以它会从服务器获取几个ACK。要解决此问题,每个工作消息都需要有一个 ID,您可以将其保存到磁盘(以防故障),或者请求必须是幂等的。
    • 另一个问题是,如果连接丢失,客户端会因为无法连接而出现错误。这也是你必须提前准备的。

    关于redis,在这篇博客中有一个很好的持久队列示例:

    以下是官方recommendation。您可以查看github repo 了解更多信息。

    redis的没落:

    • 和rabbitmq一样,你也需要自己处理worker crash,否则正在进行的任务会丢失。
    • 您必须进行轮询。每个消费者需要每隔 X 秒询问生产者是否有任何消息。

    在我看来,这是一个最糟糕的rabbitmq。

    结论

    我最终选择了rabbitmq,原因如下:

    1. 更强大的官方在线文档,包含示例。
    2. 消费者无需轮询生产者。
    3. 错误处理就像在 redis 中一样简单。

    考虑到这一点,对于这个特定的案例,我有信心说redis在这种情况下是最糟糕的rabbitmq。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      关于实现,它们都应该很容易 - 它们都有各种语言的库,请在此处查看 redis 和此处查看 rabbitmq。老实说:我不使用 javascript,所以我不知道受人尊敬的库是如何实现或支持的。

      关于您在教程中没有找到的内容(或者可能错过了in the second one,其中有几句话是关于持久队列和持久消息以及确认消息),有一些很好的解释:

      发布者确认确实不在教程中,但有一个example on github in amqp.node's repo

      使用 rabbit mq 消息传播(在大多数情况下)像这样
      publisher -> exchange -> queue -> consumer
      并且在这些站点中的每一个站点上都需要实现某种持久性。此外,如果您使用集群和队列镜像,您将获得更高的可靠性(当然还有可用性)。

      【讨论】:

        【解决方案3】:

        我认为它们都很容易使用,因为有许多为它们开发的库。

        有几个要命名的,例如disque、bul、kue、amqplib等......

        他们的文档非常好。您可以简单地复制和粘贴并在几分钟内运行它。

        我使用seneca,seneca amqp 就是一个很好的例子

        https://github.com/senecajs/seneca-amqp-transport

        【讨论】: