有代码,
async.series(tasks, function (err) {
return callback ({message: 'tasks execution error', error: err});
});
其中,tasks
是函数数组,每个函数都执行HTTP请求(使用request
模块)并调用MongoDB API来存储数据(到MongoHQ实例)。
使用我当前的输入(~200要执行的任务),需要
[normal mode] collection cycle: 1356.843 sec. (22.61405 mins.)
但只是尝试从series
更改为parallel
,它会带来巨大的好处。几乎相同数量的任务在~30 secs
而不是~23 mins
中运行。
但是,知道没有任何东西是免费的,我试图了解这种变化的后果是什么?我可以说开放套接字的数量会更高,内存消耗更多,对数据库服务器的影响更大吗?
我运行代码的机器只有1GB的RAM Ubuntu,所以我这样应用程序挂起一次,是否可能是由于资源不足造成的?
答案 0 :(得分:5)
你的直觉是正确的,并行性不是免费的,但你当然也许能够付出代价。
使用负载测试模块(或模块集合),如nodeload,您可以量化此并行操作如何影响您的服务器,以确定它是否可接受。
如果需要,Async.parallelLimit可以是限制服务器负载的好方法,但首先,发现是否需要限制非常重要。显式测试是发现系统限制的最佳方式(eachLimit具有不同的签名,但也可以使用)。
除此之外,使用async.parallel的常见缺陷包括需要比函数提供的更复杂的控制流(从您的描述看起来似乎不适用),并且天真地在太大的集合上使用并行(例如,如果您正在编写许多文件,可能会导致您进入系统的文件描述符限制)。在1GB RAM上进行~200请求和保存操作时,我认为只要你没有在事件处理程序中进行太多按摩,你就会没事,但如果你遇到服务器挂起,parallelLimit可能是一个很好的出路。
同样,测试是解决这些问题的最佳方式。
答案 1 :(得分:3)
我想指出async.parallel
执行多个功能并发而不是(完全)并行。它更像是虚拟并行。
并发执行就像通过多任务/调度在单个CPU核心上运行不同的程序一样。真正的并行执行将在多核CPU的每个核心上运行不同的程序。这很重要,因为node.js具有单线程体系结构。
关于节点的最好的事情是你不必担心I / O.它非常有效地处理I / O.
在您的情况下,您将数据存储到MongoDB,主要是I / O.因此,并行运行它们将耗尽您的网络带宽,如果从磁盘读取/写入,则磁盘带宽也是如此。由于CPU过载,您的服务器不会挂起。
这样做的结果是,如果您的服务器负担过重,您的请求可能会失败。您可能会收到EMFILE
错误(打开的文件太多)。每个套接字都算作一个文件。通常连接是池,意味着建立连接从池中拾取套接字并在完成返回池时。您可以使用ulimit -n xxxx
增加文件描述符。
如ECONNRESET
(错误:套接字挂断),ECONNREFUSED
或ETIMEDOUT
等负担过重,您也可能会收到套接字错误。所以正确处理它们。另请检查mongoDB服务器的最大并发连接数。
最后,由于垃圾回收,服务器可能会挂起。垃圾收集在您的内存增加到某一点后启动,然后在一段时间后定期运行。最大堆内存V8可以具有大约1.5 GB,因此如果GC的内存很高,则期望GC频繁运行。如果要求更多,那么节点将与process out of memory
一起崩溃。因此,修复程序中的内存泄漏。您可以查看这些tools。
答案 2 :(得分:0)
您将看到的主要缺点是数据库服务器负载飙升。根据您的设置,这可能会也可能不会。
如果您的数据库服务器是共享资源,那么您可能希望使用async.eachLimit
来限制并行请求。
答案 3 :(得分:0)
如果多个用户连接,您将意识到差异:
在这种情况下,处理器可以处理多个操作
asynch尝试运行多个用户相对相等的多个操作
T = task
U = user
(T1.U1 = task 1 of user 1)
T1.U1 => T1.U2 => T2.U1 => T8.U3 => T2.U2 => etc
这是atomicy的对话(所以也许在特殊的db操作上注意atomicy - 但那是另一个话题)
所以也许使用起来更快:
T2.U1 before T1.U1
- 直到
才会有问题T2.U1 is based on T1.U1
- 这可以通过使用回调/或因此回调来防止
...希望这是你想知道的......这有点晚了