17

ノード mysql ライブラリを使用して、EC2 の node.js アプリで発生している MySQL エラーを再現しようとしています。

接続が失われました: サーバーが接続を閉じました。

エラーをローカルで再現することはできません。データベースの強制終了は私のコードで問題なく処理されます。数秒ごとに再チェックし、再起動するとデータベースに再接続します。EC2 では、太平洋時間の午前 4 時頃に発生しますが、データベースはまだ正常に稼働しています。

そうしたいです。

  1. ローカル mysql でクラッシュを再現する
  2. これを処理するために必要なロジックを mysql ヘルパー モジュールに追加します。

私のnode.jsアプリのエラーは次のとおりです。

2012-10-22T08:45:40.518Z - エラー: uncaughtException date=Mon Oct 22 2012 08:45:40 GMT+0000 (UTC)、pid=14184、uid=0、gid=0、cwd=/home/ec2 -user/my-app, execPath=/usr/bin/nodejs, version=v0.6.18, argv=[/usr/local/bin/node, /home/ec2-user/my-app/app.js, - -my-app]、rss=15310848、heapTotal=6311392、heapUsed=5123292、loadavg=[0.0029296875、0.0146484375、0.04541015625]、uptime=3238343.511107486、ec trace=[column=13、2=my-user/home/ app/node_modules/mysql/lib/protocol/Protocol.js, function=Protocol.end, line=63, method=end, native=false, column=10, file=stream.js, function=Socket.onend, line= 80、メソッド=onend、ネイティブ=false、列=20、ファイル=events.js、関数=Socket.emit、行=88、メソッド=発行、ネイティブ=false、列=51、ファイル=net.js、関数= TCP.onread、行 = 388、メソッド = onread、ネイティブ = false]、スタック = [エラー: 接続が失われました:サーバーが接続を閉じました。,
Protocol.end (/home/ec2-user/my-app/node_modules/mysql/lib/protocol/Protocol.js:63:13)、Socket.onend (stream.js:80:10)、Socket.エミット (events.js:88:20)、TCP.onread (net.js:388:51) で]

これが私のコードです(mysqlヘルパーモジュール):

module.exports = function (conf,logger) {
  var mysql = require('mysql');

  var connectionState = false;
  var connection = mysql.createConnection({
    host: conf.db.hostname,
    user: conf.db.user,
    password: conf.db.pass,
    database: conf.db.schema,
    insecureAuth: true
  });

  function attemptConnection(connection) {
    if(!connectionState){
      connection = mysql.createConnection(connection.config);
      connection.connect(function (err) {
        // connected! (unless `err` is set)
        if (err) {
          logger.error('mysql db unable to connect: ' + err);
          connectionState = false;
        } else {
          logger.info('mysql connect!');
          connectionState = true;
        }
      });
      connection.on('close', function (err) {
        logger.error('mysqldb conn close');
        connectionState = false;
      });
      connection.on('error', function (err) {
        logger.error('mysqldb error: ' + err);
        connectionState = false;

        /*
        if (!err.fatal) {
          return;
        }
        if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
          throw err;
        }
        */
      });
    }
  }
  attemptConnection(connection);

  var dbConnChecker = setInterval(function(){
    if(!connectionState){
      logger.info('not connected, attempting reconnect');
      attemptConnection(connection);
    }
  }, conf.db.checkInterval);

  return connection;
};
4

5 に答える 5

14

node-mysql のmysql プール機能を確認してください

var mysql = require('mysql');
var pool  = mysql.createPool({
  host     : 'example.org',
  user     : 'bob',
  password : 'secret'
});

pool.getConnection(function(err, connection) {
  // connected! (unless `err` is set)
  connection.end();
});
于 2013-06-04T16:28:58.797 に答える
9

私は同様の問題を抱えていて、呼び出し元に返す前にmysql接続の状態をチェックし、必要に応じて接続を再確立するgetConnection()ラッパー関数を作成しました。私のテストでは、アプリケーションの致命的および非致命的な接続の問題を透過的に処理しました。接続が単にタイムアウトした場合、アプリケーションはエラーを発生させることなく回復します。一時的ではあるが致命的なデータベース接続の問題がある場合、データベース接続が再び利用可能になるとすぐに、アプリケーションは自動的に機能を再開します。

テストのために問題を再現する限り、[mysqld]ブロックの下のmy.iniまたはmy.cnfファイルに次の2行を追加します。

interactive_timeout=30
wait_timeout=30

これが私が「database.js」と名付けたファイルの内容です:

var mysql = require("mysql");
var CONFIG = require(__dirname + "/configuration");

module.exports.getConnection = function() {
    // Test connection health before returning it to caller.
    if ((module.exports.connection) && (module.exports.connection._socket)
            && (module.exports.connection._socket.readable)
            && (module.exports.connection._socket.writable)) {
        return module.exports.connection;
    }
    console.log(((module.exports.connection) ?
            "UNHEALTHY SQL CONNECTION; RE" : "") + "CONNECTING TO SQL.");
    var connection = mysql.createConnection({
        host     : CONFIG.db.host,
        user     : CONFIG.db.user,
        password : CONFIG.db.password,
        database : CONFIG.db.database,
        port     : CONFIG.db.port
    });
    connection.connect(function(err) {
        if (err) {
            console.log("SQL CONNECT ERROR: " + err);
        } else {
            console.log("SQL CONNECT SUCCESSFUL.");
        }
    });
    connection.on("close", function (err) {
        console.log("SQL CONNECTION CLOSED.");
    });
    connection.on("error", function (err) {
        console.log("SQL CONNECTION ERROR: " + err);
    });
    module.exports.connection = connection;
    return module.exports.connection;
}

// Open a connection automatically at app startup.
module.exports.getConnection();

// If you've saved this file as database.js, then get and use the
// connection as in the following example:
// var database = require(__dirname + "/database");
// var connection = database.getConnection();
// connection.query(query, function(err, results) { ....
于 2013-01-16T15:19:17.010 に答える
3

これが私が最終的に使用したもので、かなりうまくいきました。時折接続が失われたり再起動したりすると、うまく回復しました。接続を確立して定期的にチェックする database.js ファイルがあります。

リクエストを行うには:

var conn = require('./database');
var sql = 'SELECT foo FROM bar;';
conn.query(sql, [userId, plugId], function (err, rows) {
   // logic
}

ここに私のdatabbase.jsがあります

var mysql = require('mysql');
var Common = require('./common');
var conf = Common.conf;
var logger = Common.logger;

var connectionState = false;
var connection = mysql.createConnection({
  host: conf.db.hostname,
  user: conf.db.user,
  password: conf.db.pass,
  database: conf.db.schema,
  insecureAuth: true
});
connection.on('close', function (err) {
  logger.error('mysqldb conn close');
  connectionState = false;
});
connection.on('error', function (err) {
  logger.error('mysqldb error: ' + err);
  connectionState = false;
});

function attemptConnection(connection) {
  if(!connectionState){
    connection = mysql.createConnection(connection.config);
    connection.connect(function (err) {
      // connected! (unless `err` is set)
      if (err) {
        logger.error('mysql db unable to connect: ' + err);
        connectionState = false;
      } else {
        logger.info('mysql connect!');

        connectionState = true;
      }
    });
    connection.on('close', function (err) {
      logger.error('mysqldb conn close');
      connectionState = false;
    });
    connection.on('error', function (err) {
      logger.error('mysqldb error: ' + err);

      if (!err.fatal) {
        //throw err;
      }
      if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
        //throw err;
      } else {
        connectionState = false;
      }

    });
  }
}
attemptConnection(connection);

var dbConnChecker = setInterval(function(){
  if(!connectionState){
    logger.info('not connected, attempting reconnect');
    attemptConnection(connection);
  }
}, conf.db.checkInterval);

// Mysql query wrapper. Gives us timeout and db conn refreshal! 
var queryTimeout = conf.db.queryTimeout;
var query = function(sql,params,callback){
  if(connectionState) {
    // 1. Set timeout
    var timedOut = false;
    var timeout = setTimeout(function () {
      timedOut = true;
      callback('MySQL timeout', null);
    }, queryTimeout);

    // 2. Make query
    connection.query(sql, params, function (err, rows) {
      clearTimeout(timeout);
      if(!timedOut) callback(err,rows);
    });
  } else {
    // 3. Fail if no mysql conn (obviously)
    callback('MySQL not connected', null);
  }
}

// And we present the same interface as the node-mysql library!
// NOTE: The escape may be a trickier for other libraries to emulate because it looks synchronous
exports.query = query;
exports.escape = connection.escape;
于 2013-03-16T11:36:17.910 に答える
0

generic-poolを使用して、ローカルで機能するものを作成しました。私はそれをテストして、サーバー側で奇妙な方法でクラッシュしないかどうかを確認すると思います。

// Test node connection pool stuff

// Create a MySQL connection pool with
// a max of 10 connections, a min of 2, and a 30 second max idle time
var poolModule = require('generic-pool');
var pool = poolModule.Pool({
    name     : 'mysql',
    create   : function(callback) {
        var Client = require('mysql').Client; // use node-mysql library in all it's dubious glory
        var c = new Client();
        c.user     = 'root';
        c.password = 'xxx';
        c.database = 'test';
        c.on('close', function (err) {
          console.log('mysqldb conn close');
        });
        c.on('error', function (err) {
          console.log('mysqldb error: ' + err);
        });

        // parameter order: err, resource
        // new in 1.0.6
        callback(null, c);
    },
    destroy  : function(client) { client.end(); },
    max      : 10,
    // optional. if you set this, make sure to drain() (see step 3)
    min      : 2, 
    // specifies how long a resource can stay idle in pool before being removed
    idleTimeoutMillis : 30000,
     // if true, logs via console.log - can also be a function
    log : true 
});

var http = require('http');
http.createServer(function (req, res) {

  // Get db conn
  pool.acquire(function(err, client) {
      if (err) {
          // handle error - this is generally the err from your
          // factory.create function 
          console.log('pool.acquire err: ' + err);
          res.writeHead(500, {'Content-Type': 'application/json'});
          out = {
            err: err
          }
          res.end(JSON.stringify(out));
      }
      else {
          client.query("select * from foo", [], function(err, results) {

              if(err){
                res.writeHead(500, {'Content-Type': 'application/json'});
                out = {
                  err: err
                }
                res.end(JSON.stringify(out));
              } else {
                res.writeHead(500, {'Content-Type': 'application/json'});
                out = {
                  results: results
                }
                res.end(JSON.stringify(out));
              }


              // return object back to pool
              pool.release(client);
          });
      }
  });
}).listen(9615);

明らかな理由もなく、午前4時に死なないでください。

于 2012-10-22T22:32:58.810 に答える