关于node.js:node和heroku的负载平衡

Load Balancing with Node and Heroku

我有一个接受iOS应用程序的API请求的Web应用程序。我的网络应用程序在Heroku上使用免费的Dyno托管,它可以处理每个请求512MB的数据。因为节点是单线程应用程序,所以一旦我们开始从iOS端获得更高级别的流量到Web服务器,这将是一个问题。我也不是世界上最富有的人,所以我想知道创建另一个免费的Heroku应用程序并使用循环方法来平衡从iOS应用程序收到的负载是否明智?

我只需要指出正确的方向。在财政上,垂直伸缩并不是一个真正的选择。


我是Heroku的node.js平台所有者。

您可能正在进行一些过早的优化。在我们最小的1X大小(512MBRAM)上,node.js可以每分钟处理数百个同时连接和数千个请求。

如果你的iOS应用程序一直在最大限度地利用这一点,那么是时候考虑货币化了!


正如丹尼尔所说,这违反了英雄的规则。尽管如此,可能还有其他的服务可以让你做到这一点。解决这个问题的一种方法是使用带有zeromq的集群模块(在使用模块之前需要安装zeromq—请参阅模块描述)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var cluster = require('cluster');
var zmq = require('zmq');

var ROUTER_SOCKET = 'tcp://127.0.0.1:5555';
var DEALER_SOCKET = 'tcp://127.0.0.1:7777';

if (cluster.isMaster) {
  // this is the main process - create Router and Dealer sockets
  var router = zmq.socket('router').bind(ROUTER_SOCKET);
  var dealer = zmq.socket('dealer').bind(DEALER_SOCKET);

  // forward messages between router and dealer
  router.on('message', function() {
    var frames = Array.prototype.slice.cal(arguments);
    dealer.send(frames);
  });

  dealer.on('message', function() {
    var frames = Array.prototype.slice.cal(arguments);
    router.send(frames);
  });

  // listen for workers processes to come online
  cluster.on('online', function() {
    // do something with a new worker, maybe keep an array of workers
  });

  // fork worker processes
  for (var i = 0, i < 100; i++) {
    cluster.fork();
  }
} else {
  // worker process - connect to Dealer
  let responder = zmq.socket('rep').connect(DEALER_SOCKET);

  responder.on('message', function(data) {
    // do something with incomming data
  })
}

这只是为了给你指明正确的方向。如果您考虑一下,您可以用一个参数创建一个脚本,该参数将告诉它是主进程还是工作进程。然后在主服务器上按原样运行它,在其他服务器上使用worker标志运行它,这将强制它连接到主经销商。

现在,您的主应用程序需要将请求发送到路由器,路由器稍后将转发到工作进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var zmq = require('zmq');
var requester = zmq.socket('req');

var ROUTER_SOCKET = 'tcp://127.0.0.1:5555';

// handle replies - for example completion status from the worker processes
requester.on('message', function(data) {
  // do something with the replay
});

requester.connect(ROUTER_SOCKET);

// send requests to the router
requester.send({
  // some object describing the task
});


因此,首先,正如其他回复所指出的,运行两个应用程序副本以避免Heroku的限制违反了他们的TOS,这可能不是一个好主意。

然而,有一些好消息。对于初学者(来自Heroku的文档):

The dyno manager will restart your dyno and log an R15 error if the memory usage of a:

  • free, hobby or standard-1x dyno reaches 2.5GB, five times its quota.

据我所知,尽管您的Dyno有512MB的实际RAM,但在实际重新启动之前,它将换成5倍的内存。因此,您可以超过512MB(只要您愿意支付交换到磁盘的性能损失,这可能很严重)。

除此之外,Heroku会在第二个阶段进行计费,并允许你根据需要上下调整你的Dyno阵型。通过点击Heroku API,在你自己的应用程序中很容易做到这一点——我看到你已经用nodejs标记了这一点,所以你可能想看看:

  • Heroku的节点客户端
  • 非常简单但仍能正常工作的toots/node heroku模块

这两个模块都允许您放大和缩小Dyno的组成——通过一个简单的启发式(比如,总是有一个备用的1X Dyno运行),您可以在处理请求时增加容量,在API请求不运行时去掉备用容量。考虑到你是按秒计费的,这最终可能是非常便宜的;1X达诺系统的运行时间大约是每小时5美分。如果你最终一天要运行几个小时的额外的Dynos,对你来说这是一个非常非常小的成本。

最后:还有第三方服务,如Adept和HireFire(两个随机的例子来自Google,我相信还有更多)可以让你在某种程度上实现自动化,但我对它们没有任何经验。


你当然可以,我的意思是,编程-但那将绕过希罗库的任务:

4.4 You may not develop multiple Applications to simulate or act as a single Application or otherwise access the Heroku Services in a manner intended to avoid incurring fees.

现在,我不确定:

Because node is a single threaded application this will be a problem once we start getting higher levels of traffic from the ios end to the web server.

有一些主题讨论这个问题,并给出一些有趣的答案:

大流量生产环境下的集群节点JS

如何决定何时使用node.js?

此外,他们还链接到这段视频,介绍了node.js,其中介绍了一些基准测试:

Ryan Dahl介绍的节点JS