NodeJS – 处理超过100个并发连接的内存

我正在开发物联网应用程序,客户端每2秒向服务器发送生物潜在信息。 客户端每2秒发送一个包含400行数据的CSV文件。 我的服务器上运行了一个Socket.IO websocket服务器,它从每个客户端捕获这些信息。 一旦捕获到这些信息,服务器必须每隔2秒将这400条logging存入一个mysql数据库。 虽然只要客户端数量很小,这种方式就可以很好地工作,但随着客户端数量的增长,服务器开始抛出“进程内存exception”。

以下是收到的例外:

<--- Last few GCs ---> 98522 ms: Mark-sweep 1397.1 (1457.9) -> 1397.1 (1457.9) MB, 1522.7 / 0 ms [allocation failure] [GC in old space requested]. 100059 ms: Mark-sweep 1397.1 (1457.9) -> 1397.0 (1457.9) MB, 1536.9 / 0 ms [allocation failure] [GC in old space requested]. 101579 ms: Mark-sweep 1397.0 (1457.9) -> 1397.0 (1457.9) MB, 1519.9 / 0 ms [last resort gc]. 103097 ms: Mark-sweep 1397.0 (1457.9) -> 1397.0 (1457.9) MB, 1517.9 / 0 ms [last resort gc]. <--- JS stacktrace ---> ==== JS stack trace ========================================= Security context: 0x35cc9bbb4629 <JS Object> 2: format [/xxxx/node_modules/mysql/node_modules/sqlstring/lib/SqlString.js:~73] [pc=0x6991adfdf6f] (this=0x349863632099 <an Object with map 0x209c9c99fbd1>,sql=0x2dca2e10a4c9 <String[84]: Insert into rent_66 (sample_id,sample_time, data_1,data_2,data_3) values ? >,values=0x356da3596b9 <JS Array[1]>,stringifyObjects=0x35cc9bb04251 <false>,timeZone=0x303eff... FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory Aborted 

以下是我的服务器的代码:

 var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var mysql = require('mysql'); var conn = mysql.createConnection({ host: '<host>', user: '<user>', password: '<password>', database: '<db>', debug: false, }); conn.connect(); io.on('connection', function (socket){ console.log('connection'); var finalArray = [] socket.on('data_to_save', function (from, msg) { var str_arr = msg.split("\n"); var id = str_arr[1]; var timestamp = str_arr[0]; var data = str_arr.splice(2); finalArray = []; var dataPoint = []; data.forEach(function(value){ dataPoint = value.split(","); if(dataPoint[0]!=''){ finalArray.push([dataPoint[0],1,dataPoint[1],dataPoint[2],dataPoint[3]]); finalArray.push([dataPoint[0],1,dataPoint[4],dataPoint[5],dataPoint[5]]); } }); var sql = "Insert into rent_"+id+" (sample_id,sample_time, channel_1,channel_2,channel_3) values ? "; var query = conn.query (sql, [finalArray],function(err,result){ if(err) console.log(err); else console.log(result); }); conn.commit(); console.log('MSG from ' + str_arr[1] + ' ' + str_arr[0] ); }); }); http.listen(9000, function () { console.log('listening on *:9000'); }); 

我能够让服务器处理100个并发连接,之后我开始接收进程内存exception。 在引入数据库插入之前,服务器将简单地将csv作为文件存储在磁盘上。 通过这个设置,服务器能够处理1200多个并发连接。

基于互联网上可用的信息,看起来像数据库插入查询(这是asynchronous的)在内存中持有400行数组,直到插入通过。 结果,随着客户端数量的增长,服务器的内存足迹增加,从而最终耗尽内存。

我经历了许多关于--max_old_space_sizebuild议,我不确定这是一个长期的解决scheme。 另外,我不确定应该在什么基础上决定应该在这里提到的价值。

另外,我也经历了关于asynchronous实用程序模块的build议。 但是,串行插入数据可能会在客户端插入数据和服务器将此数据保存到数据库之间引入巨大的延迟。

我多次围绕这个问题进行了讨论。 有没有办法服务器可以处理来自1000多个并发客户端的信息,并以最小的延迟将数据保存到Mysql数据库中。 我在这里碰到了一个路障,在这方面的任何帮助都非常感谢。

我会总结一下我的意见,因为他们发送了正确的道路来解决您的问题。

首先,你必须确定问题是否是由你的数据库引起的。 最简单的方法是将数据库部分注释掉,看看可以扩展的程度。 如果你遇到了没有内存或CPU问题的数千人,那么你的注意力可能转移到搞清楚为什么把数据库代码添加到混合中导致问题。

假设问题是由数据库引起的,那么当有大量的活动数据库请求时,你需要开始理解它是如何处理的。 通常情况下,忙碌的数据库首先要使用连接池 。 这给你三个主要的事情,可以帮助规模。

  1. 它使您可以快速重复使用先前打开的连接,因此您不必每个操作都创build自己的连接,然后closures连接。
  2. 它允许您同时指定池中同时连接数据库的最大数量(控制您在数据库上的最大负载,也可能限制它将使用的最大内存量)。 超出限制的连接将会排队(这通常是您在高负载情况下所需要的,所以您不会压倒所拥有的资源)。
  3. 它使得查看连接泄漏问题变得更容易,而不仅仅是泄露连接,直到耗尽了一些资源,在testing中池将很快变空,并且服务器将无法处理更多的事务(所以你更有可能在testing中看到问题)。

那么,您可能还需要查看数据库连接的事务处理时间,以了解它们可以处理任何特定事务的速度。 你知道你正在处理多less个事务/秒,所以你需要看看你的数据库以及它的configuration和资源(内存,CPU,磁盘的速度等等)是否能够跟上你的负载想扔在它。