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,我会获得相同的功能吗?
bash: ./Main.js: Heroku 上的权限被拒绝