快速有效地创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。
- 在Google文档的Google驱动器API中的files.list()和files.get()中缺lessexportLinks
- nodejs https api请求错误错误:在TLSWrap.onread(net.js:568:26)处的exports._errnoException(util.js:1018:11)处读取ECONNRESET
- 是否有一个Raml 1.0(不是0.8)的HTML生成器?
- Node.js应用程序收到GET请求到API的空响应
- 我应该如何构build我的数据库和API服务器为基于回合的多人iPhone的棋盘游戏? (考虑nodejs,mongo,沙发等)
- 为request.post设置内容types的标题为json
- 如何将API调用限制到AWS EC2上的节点应用程序
- Node Express API +前端
- 如何使用nodejs和express在REST API中实现search和过滤