在Heroku上使用单个Dyno的Node.js子进程

15

请原谅我的无知,我目前正在学习如何使用Node,而我之前只有PHP背景,并没有接触过Apache或服务器管理。我正在使用Heroku来托管我的Node项目,直接从Cloud9 IDE上推送。

据我所了解,Heroku dyno是一个单个的Web进程,购买额外的dyno将允许您处理更多的流量,因为通过增加dyno,可以增加您一次处理请求的数量。

我知道Node是一个单线程的系统,逐个处理请求,允许您为任何可能需要一些时间处理的事情(如数据库请求、处理文件等)生成子进程。

那么在使用单个dyno生成子进程时,在Heroku中会发生什么呢?这不需要另一个dyno来工作吗?如果Node正在运行一个单独的进程,并且我只有一个进程可用于我的单个dyno中,任何额外的进程也将由该进程处理,这样岂不是会出现问题?

还是我完全理解错了?


1
你不应该启动单独的节点进程来异步进行数据库请求和文件处理...无需这样做就是使用Nodejs的好处。如果您正在生成一个非确定性数量的工作线程/进程,则绝对错误地使用了NodeJS。有了这个答案,我相信你应该能够回答自己的问题了。如果您需要更多详细信息,请让我知道! - MobA11y
谢谢你的回复,Chris。我可能没有表达清楚——我目前对Node的了解不太超出《Node入门》一书中的内容,其中一个例子使用var exec = require("child_process").exec;,然后稍后使用exec函数执行昂贵的shell操作以演示非阻塞代码。因此,据我所知,在这个例子中,shell操作被推迟到另一个进程中,以便主进程可以继续接受新请求,并在以后接收回调以显示最初请求的响应。 - mibbler
我将我的评论作为答案提交了。 - MobA11y
1个回答

9
你对exec的理解大概是正确的,但我的担忧在于你在不必要的情况下使用它。在你的问题中,你只提到了I/O类型的操作,而Node在其单线程事件模型中非常高效地处理这些操作。尽管是单线程的,但事件模型允许代码在不阻塞主事件循环的情况下运行(除非你正在进行非常耗费CPU资源的操作,其中数据库请求和文件处理不包括在内)。话虽如此,你不应该需要启动一个额外的dyno来完成你想要的事情。
把dyno想象成一台单处理器计算机。在具有单个处理器的机器上可以做的任何事情,你都可以在你的dyno上做,而无需额外收费或创建dyno。但是,与单核处理器计算机相比,dyno的内存要少得多。因此,你希望产生的任何子进程都不需要在另一个dyno上运行。每个你想要运行的主进程都需要自己的dyno。
var http = require('http');

http.createServer(function (req, res) {

    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('An amount of data that will take 1 second to send');//This will not block the event loop
}).listen(1337, '127.0.0.1');

var http = require('http');
http.createServer(function (req, res) {

    while(true) {
         break after 1 second; //this will block the event loop for 1 second
    }

    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

考虑上面代码中的两个服务器。这两个服务器都有大约一秒钟的工作时间。第一个例子可以每秒服务成千上万个请求,而第二个例子只能处理一个请求。发送数据、数据库请求、服务器请求、文件IO等所有操作都会像第一个例子一样运行……很少有Node的行为像第二个例子那样。如果你有符合第二个例子的需求,那么最好选择其他编程语言,而不是试图强制使用Node来完成它,因为它的设计非常不适合这种用例。

哦,好的。所以看来我把单进程和单线程搞混了..?你知道在一个 dyno 上可以运行的进程数量是否有限制吗? - mibbler
我强烈反对您启动大量进程。如果您认为您的节点进程需要启动超过1或2个处理器的工作程序,那么您可能没有正确使用节点,或者您的用例最好适用于其他编程语言。我将为您编写一个小演示代码。话虽如此,这个数字可能仅受Heroku使用的操作系统限制,而不是任何他们希望对您施加的限制。 - MobA11y
1
因此,您真正的限制可能是RAM。 Dynos可以支持512MB的RAM(上次我检查是一段时间以前)。当您分叉一个进程时,该进程的内存会随着您的操作而复制到自己的环境中。因此,假设有一个100MB的进程,您可以生成5个这样的进程。(这里的数学并不完全准确,这只是一个概述,可能需要进行基准测试) - MobA11y
非常感谢您提供的代码示例。那么,假设第一个服务器将获取一些数据并使用它来执行类似于curl的请求到另一个响应缓慢、需要3秒钟才能响应的站点,然后返回该站点的数据。这会造成阻塞吗?还是Node会自动以非阻塞的方式处理它? - mibbler
每当您在节点函数中看到接受回调函数参数,这是一个不会阻塞事件循环并且将表现得像第一个示例的函数。通常情况下,如果您使用节点库函数,则无需担心阻塞事件循环,并且应将该代码块视为在其自己的线程上运行(虽然实际上并非如此,但如果您以这种方式考虑它,比试图理解 V8 如何处理您的代码要容易得多)。 - MobA11y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接