クライアントが生体電位情報を2秒ごとにサーバーに送信するIoTアプリケーションで作業しています。クライアントは、2秒ごとに400行のデータを含むCSVファイルを送信します。私は各クライアントからこの情報を取得する私のサーバー上で実行されているSocket.IO websocketサーバーを持っています。この情報が取得されると、サーバは各クライアントに対して2秒ごとに400レコードをmysqlデータベースにプッシュする必要があります。クライアントの数が少ないほど、これは完璧に機能しましたが、クライアントの数が増えてサーバーが「メモリ不足例外の例外」を投げ始めました。続きNodeJS - 100以上の同時接続でメモリ不足を処理する
は、受け取った例外です:後
<--- 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の同時接続を処理するために取得することができましたメモリ不足例外。データベースの挿入が導入される前に、サーバは単にcsvをディスク上のファイルとして保存します。この設定で、サーバーは1200以上の同時接続を処理できました。
インターネット上の情報に基づいて、データベース挿入クエリ(非同期型)は、挿入が完了するまでメモリ内の400行配列を保持しているようです。結果として、クライアントの数が増えると、サーバのメモリフットプリントが増加し、最終的にはメモリが不足する。
私は--max_old_space_size
に関してインターネット上で多くの提案をしましたが、これは長期的な解決策ではないと私は確信しています。また、私はここで言及すべき価値をどのような根拠で決めなければならないのかは分かりません。
また、私は非同期ユーティリティモジュールについての提案を行ってきました。ただし、データを連続して挿入すると、クライアントがデータを挿入する時刻と、サーバーがこのデータをデータベースに保存する時刻との間に大きな遅延が発生する可能性があります。
私はこの問題を何回か周りに回りました。サーバが1000以上の同時クライアントからの情報を処理し、そのデータを最小レイテンシでMysqlデータベースに保存する方法はありますか?私はここに道路ブロックを打って、この方向への助けを非常に感謝しています。
これはあなたのコードにどのようになっているのか分かりませんが、この中の引用符は正当なJavascriptではありません: 'socket.on(' data_to_save '、...) '。 – jfriend00
私はMySQLのエキスパートではありません。より良い設定で良い解決策が生まれるかもしれません。あるいは、より軽量なDBシステムMongoDBに行くことをお勧めします。 – Pac0
私は最初にあなたのデータベースコードをコメントして、受信したメッセージだけを処理できるかどうかを確認します。それをうまく処理できれば、問題はDBコード(多分メモリまたはリソースリーク)にあります。 – jfriend00