Heroku 上的 Node JS 消息队列

Posted

技术标签:

【中文标题】Heroku 上的 Node JS 消息队列【英文标题】:Node JS message queue on Heroku 【发布时间】:2016-06-27 01:11:51 【问题描述】:

我需要将运行在 Heroku 上的 Node JS 服务器移动到消息队列架构中。目前,服务器接收到一个 HTTP 请求,做一些处理,然后响应。问题是处理需要一些时间,尤其是当有很多请求时。这种冗长的处理时间会导致服务器超时、过载和崩溃!我的阅读告诉我需要一个后台工作人员来进行处理。

我对消息队列和后台工作人员的经验为零,我正在寻找一个非常简单的示例来入门。任何人都可以建议一个简单易懂的模块或示例来开始吗?

我找到了一些examples,但它们很复杂,我迷路了!我想要一个可以构建的准系统示例。

【问题讨论】:

酷。你有我能看到的截屏视频的预览/示例吗?我想看看这是否是正确的水平。你教的内容适用于 Heroku 吗? 其中一个采访是免费的,在这里:sub.watchmecode.net/episode/rmq-interviews-udi-dahan 但我没有太多可以预览的东西,否则......我应该整理一个预览视频 【参考方案1】:

让我们看看如何使用 RabbitMQ 做到这一点。 首先,您需要在开发环境中使用 RabbitMQ 服务器。 如果您还没有它(检查“sudo service rabbitmq-server status”),您可以安装(在 ubuntu 或类似设备上),如下所示:

sudo su -c "echo 'deb http://www.rabbitmq.com/debian/ testing main' >> /etc/apt/sources.list"
wget http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
sudo apt-key add rabbitmq-signing-key-public.asc
sudo apt-get update
sudo apt-get install rabbitmq-server
rm  rabbitmq-signing-key-public.asc

然后,让服务器运行:

sudo service rabbitmq-server start

您还需要为 Heroku 部署配置 RabbitMQ 服务。让我们在此示例中使用 CloudAMPQ。您可以通过以下方式将其免费计划添加到您的 Heroku 应用:

heroku addons:create cloudamqp:lemur 

这将在您的 Heroku 应用中创建一个新的 CLOUDAMQP_URL 环境变量。

接下来,您将需要一个适合您的 node.js 应用程序的 RabbitMQ 客户端。 其中有一些,但对于这个例子,让我们使用 ampqlib:

npm install ampqlib --save

这应该在您的 package.json 依赖项中添加类似于以下行的内容:

"amqplib": "^0.4.1",

接下来是为您的 Heroku 应用添加一个后台“worker”测功机。 我假设目前您的 Procfile 中只有一个 Web dyno。 所以,你需要添加另一行来实例化一个worker,例如:

worker: node myworker.js

最后,您需要编写代码,使您的 Web dyno 能够通过 RabbitMQ 与您的 worker dyno 进行交互。

为了这个例子,我假设您的 Web dyno 将“发布”消息到 RabbitMQ 消息队列,而您的 worker dyno 将“消费”这些消息。

所以,让我们从编写发布到消息队列的代码开始吧。此代码需要在您的 Web dyno 中的某个位置运行:

// Define ampq_url to point to CLOUDAMPQ_URL on Heroku, or local RabbitMQ server in dev environment
var ampq_url = process.env.CLOUDAMQP_URL || "amqp://localhost";
var ampq_open = require('amqplib');
var publisherChnl;

function createPublisherChannel() 

    // Create an AMPQ "connection"
    ampq_open.connect(ampq_url)
        .then(function(conn) 
            // You need to create at least one AMPQ "channel" on your connection   
            var ok = conn.createChannel();
            ok = ok.then(function(ch)
                publisherChnl = ch;
                // Now create a queue for the actual messages to be sent to the worker dyno 
                publisherChnl.assertQueue('my-worker-q');
            )
        )
    

function publishMsg() 
     // Send the worker a message
     publisherChnl.sendToQueue('my-worker-q', new Buffer('Hello world from Web dyno'));

您需要在 Web dyno 初始化期间调用 createPublisherChannel()。然后,只要您想向队列发送消息,就调用 publishMsg()。

最后,让我们编写在worker dyno中消费上述消息的代码。因此,例如,在 myworker.js 中添加如下内容:

// Just like in Web dyno...
var amqp_url = process.env.CLOUDAMQP_URL || "amqp://localhost";
var open_ampq = require('amqplib').connect(amqp_url);
var consumerChnl;    

// Creates an AMPQ channel for consuming messages on 'my-worker-q'
function createConsumerChannel()      
    open_ampq
        .then(function(conn) 
            conn.createChannel()
                .then(function(ch) 
                    ch.assertQueue('my-worker-q');
                    consumerChnl = ch;
            );
        );
  

function startConsuming() 
    consumerChnl.consume('my-worker-q', function(msg)
        if (msg !== null) 
            console.log(msg.content.toString());
            // Tell RabbitMQ server we have consumed the message
            consumerChnl.ack(msg);
        
    )
 

createConsumerChnl().then(startConsuming); 

最后,使用“heroku local”进行测试。您应该会看到您的应用程序中正在运行 2 个进程,“Web”和“worker”。每当您在 Web dyno 中调用 publishMsg() 时,您应该希望看到 wroker dyno 将消息内容吐出到您的控制台。要查看您的 RabbitMQ 队列中发生了什么,您可以使用:

sudo rabbitmqctl list_queues

【讨论】:

感谢您的解释,这很有帮助。不过我有一个问题.. 我如何在不同模块之间共享这个 publisherChnl? 我假设您的意思是您希望能够从 Web 应用程序中的多个 node.js 模块在队列上发布消息?如果是这样,只需使用“exports.publishMsg = publishMsg”导出函数 publishMsg,以便您可以从任何地方调用它。如果这不是您的意思,请澄清。 是的,这是我的问题。感谢您的澄清。我还有一个疑问。我尝试了这段代码,看起来 startConsuming() 在 createConsumerChannel() 完成之前运行。链接它的最佳方法是什么?我可以在consumerChnl = ch; 之后调用 startConsuming() 来工作,但这是正确的方法吗?【参考方案2】:

我在这里找到了一个非常简单的例子(后面是更深入的例子):https://www.rabbitmq.com/tutorials/tutorial-one-javascript.html

【讨论】:

以上是关于Heroku 上的 Node JS 消息队列的主要内容,如果未能解决你的问题,请参考以下文章

对于实时 node.js 消息传递应用程序,如果没有 Heroku 中的 websockets,我会获得相同的功能吗?

消息模型:主题和队列的区别

从 node.js 中的消息队列中读取消息

bash: ./Main.js: Heroku 上的权限被拒绝

从 Array 推送到 Azure 队列覆盖消息?[node.JS]

消息队列助你成为高薪 Node.js 工程师