2015-11-21 79 views
13

我的用例如下: 我從我的節點服務器向公共API發出大量其他API調用。有時反應很大,有時候很小。我的用例要求我將響應JSON串聯起來。我知道一個大的JSON作爲響應會阻止我的事件循環。經過一番研究,我決定使用child_process.fork來解析這些響應,以便其他API調用不需要等待。我嘗試從我的主進程發送一個30 MB的JSON文件到分叉的child_process。子進程需要很長時間來挑選和解析json。從孩子的過程中期待的迴應並不是很大。我只是想串起並得到長度併發送回主流程。Node.js - 將大對象發送給child_process的速度很慢

我附上了主代碼和子代碼。

var moment = require('moment'); 
var fs = require('fs'); 
var process = require('child_process'); 
var request = require('request'); 

var start_time = moment.utc().valueOf(); 

request({url: 'http://localhost:9009/bigjson'}, function (err, resp, body) { 

    if (!err && resp.statusCode == 200) { 

    console.log('Body Length : ' + body.length); 

    var ls = process.fork("response_handler.js", 0); 

    ls.on('message', function (message) { 
     console.log(moment.utc().valueOf() - start_time); 
     console.log(message); 
    }); 
    ls.on('close', function (code) { 
     console.log('child process exited with code ' + code); 
    }); 
    ls.on('error', function (err) { 
     console.log('Error : ' + err); 
    }); 
    ls.on('exit', function (code, signal) { 
     console.log('Exit : code : ' + code + ' signal : ' + signal); 
    }); 
    } 
    ls.send({content: body}); 
}); 

response_handler.js

console.log("Process " + process.argv[2] + " at work "); 

process.on('message', function (json) { 
    console.log('Before Parsing'); 
    var x = JSON.stringify(json); 
    console.log('After Parsing'); 
    process.send({msg: 'Sending message from the child. total size is' + x.length}); 
}); 

有沒有更好的方式來實現什麼即時試圖做的?一方面,我需要node.js的強大功能來實現每秒1000次的API調用,但有時候我會得到一個大的JSON回來,從而導致事情發生。

+0

您的方法似乎很好。當你說「我的節點服務器」時,我知道它是一個爲客戶提供服務的過程。你真的需要從服務器內部進行API調用嗎?您不能將任務委派給不同的流程,並將它們與消息代理,Redis之類的服務器或簡單的管道或其他形式的IPC建立通信通道? – kliron

+0

我的糟糕之處在於,把這稱爲服務器,你可以認爲這是一個代理。這不是爲任何人服務。該代理充當高度可擴展的API客戶端。 – Vinoth

+0

也許你可以使用流式json解析器,而不是使用JSON在一個大塊中完成它。 – mcfedr

回答

3

您的任務似乎是IO綁定(獲取30MB大小的JSON),其中Node的異步性發光,以及CPU限制(解析30MB大小的JSON),其中異步性不會幫助您。

分叉過多的過程很快就會變成資源匱乏並降低性能。對於CPU限制任務,您只需要與核心一樣多的進程即可。

我會使用一個單獨的進程將提取和委託解析分配給N個其他進程,其中N(最多)是CPU核心數減1,並且使用某種形式的IPC進行進程通信。

一種選擇是使用節點的羣集模塊,以協調上述所有的:https://nodejs.org/docs/latest/api/cluster.html

使用這個模塊,你可以有一個主進程創建工作進程的前期,不需要時叉的後顧之憂,需要創建多少個進程等等。IPC可以像往常一樣使用process.sendprocess.on。所以一個可能的工作流程是:

  1. 應用程序啓動:主進程創建一個「fetcher」和N「分析器」進程。
  2. fetcher發送一個API端點的工作列表來處理並開始提取JSON,將其發送回主進程。
  3. 在獲取的每個JSON中,主發送給解析器進程。您可以循環方式使用它們,也可以在解析器工作隊列爲空或運行時使用更復雜的方式向主進程發送信號。
  4. 解析器進程將生成的JSON對象發送回主。

請注意,IPC也有不平凡的開銷,特別是在發送/接收大型對象時。你甚至可以讓fetcher做非常小的響應分析,而不是傳遞給他們,以避免這種情況。 「小」這裏可能是< 32KB。

另請參閱:Is it expensive/efficient to send data between processes in Node?

+0

這正是我想要做的。主線程將從各種API中獲取所有內容,計算由獨立的進程處理。這裏的問題是將響應傳遞給這些新進程。我已經給出了一個簡化的例子,它看起來像我將創建儘可能多的流程作爲響應。但我確實打算將其限制在內核數量上。但我沒有得到它如何可以由節點集羣編排。讓我知道如果我在這裏失去了一些東西。如果您有任何建議,請告訴我。感謝您的迴應。 – Vinoth

+0

@Vinoth我更新了答案。看看Cluster的文檔,它非常簡單。 – kliron

+0

我試試這個。看起來這裏的假設是管道大json解析器從主人不會花費盡可能多的時間,因爲它需要在我的例子。其中im使用child_process.fork()。由於節點集羣內部使用child_process.fork(),我想知道它如何表現不同。我給它一個鏡頭來確認。欣賞迴應。 – Vinoth