快速有效地创buildCSV文件报告,而不会减慢node.js服务器的速度

我有一个Node.js快速API,托pipe在一个Azure应用服务上,提供来自SQL服务器数据库的数据。 一个新的要求是根据可定制的数据导出报告。 这些应该是即时生成的CSV文件。

我面临的问题是,在某些情况下,CSV文件将会非常大(可能是50万行)。 我不难创build这些文件,然后将它们上传到Blob存储,或者直接将它们提供给用户。 但是,正如你可以想象的那样,这将花费一些负载在服务器上。 这个API每分钟提供约500个Post / Get请求。 Node的单线程特性意味着当有人请求类似的CSV文件时,服务器将抓取。

我需要一些build议,而不是做什么。 我的想法是启动一个新的应用程序,在一个新的服务器上(可能是一个用ASP.NET编写的),负责创buildCSV文件。 它公开一个接收参数来创build文件的结束点,然后用文件或链接进行响应。 但是,因为它是一个单独的服务器(如果我做了类似于.NET的单独线程),它在等待响应时不会降低节点服务器的速度。 这看起来好像很多工作。 有什么简单的吗? 我对任何可以直接连接到SQL数据库并生成报告的服务开放(所以我可以把它给客户端,而不是定制的报告,我需要硬编码)。

如果您不能使用另一个进程,则可以编写CSV生成代码,以便使用setImmediate来按大块计划生成。 然后它会间歇地产生,所以线程可以处理其他请求。

 const chunkSize = 1000; function generateCSV(rows, cb) { const csv = []; function handleChunk(rows, rest) { for (let row of rows) { csv.push(`${rows[i].field1},${rows[i].field2}`); } if (rest.length) { setImmediate(handleChunk, rest.slice(0, chunkSize), rest.slice(chunkSize)); } else { cb(null, csv.join('\n')); } } handleChunk(rows.slice(0, chunkSize), rows.slice(chunkSize)); } 

您遇到的问题与CSV文件操作无关。 它正在处理巨大的任务。 由于node.js是单线程的,一个庞大的任务可以“阻塞”服务器。

解决办法是把大任务分解成最小的任务。

你可以使用setTimeout()函数来做到这一点。

例如

不削减任务(任务2和3将等待,直到任务1完成)

 [ Task 1 ][Task 2][ Task 3 ] 

使用setTimeout()

 [ Task 1.0 ][ Task 1.1 ][Task 2][ Task 1.2 ][ Task 3 ][ Task 1.3 ][ Task 1.4 ] 

任务不会被阻止

(我写这并没有意识到你正在使用Azure应用程序服务,我不确定Azure应用程序服务是否允许child_process.fork,如果不是的话,这是错误的答案,尽pipe它可以帮助不同的平台上的人)。

另一个解决scheme是使用child_process.fork在另一个进程中执行繁重的任务:

 // worker.js process.on('message', msg => { process.send(makeCSV(msg)); }); // server.js const cp = require('child_process'); app.get('/', (req, res) => { const child = cp.fork('./worker.js'); child.on('message', csv => { res.send(csv); }); child.send(req.params); }); 

分叉过程相当重。 如果您希望处理大量的CSV请求,那么您可以在您的应用第一次启动时创build一个工作人员池,而不是为每个请求启动一个新的进程。 谷歌search引导我https://github.com/thisandagain/fork-pool似乎处理您的游泳池。

如果这些昂贵的CSV请求相对较less,那么https://nodejs.org/api/cluster.html#cluster_cluster也可能解决您的问题。 这会启动多个服务器进程,因此如果有一两个人忙于创buildCSV文件,那么您仍然可以自由处理其他请求的stream。