重现MySQL错误:服务器关闭连接(node.js)

nfl*_*cco 16 mysql node.js node-mysql

我正在尝试使用节点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],正常运行时间= 3238343.511107486,trace = [column = 13,file =/home/ec2-user/my- 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,method = onend,native = false,column = 20,file = events.js,function = Socket.emit,line = 88,method = emit,native = false,column = 51,file = net.js,function = TCP.onread,line = 388,method = onread,native = false],stack = [错误:连接丢失:服务器关闭了连接.
在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 helper模块):

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;
};
Run Code Online (Sandbox Code Playgroud)

Ale*_*ley 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();
});
Run Code Online (Sandbox Code Playgroud)

  • 最好用`connection.release()`替换`connection.end()`,这样它就可以重用于进一步的请求而不需要断开连接. (5认同)
  • 是的,这似乎是最好的方法,你可以将你的数据库并行作为奖励. (2认同)

小智 9

我遇到了类似的问题,并创建了一个getConnection()包装函数,该函数在将mysql连接返回给调用者之前检查mysql连接的运行状况,并根据需要重新建立连接.在我的测试中,它已经为应用程序透明地处理了致命和非致命的连接问题.如果连接只是超时,则应用程序将恢复,而不会出现任何错误.如果存在暂时但致命的数据库连接问题,则只要数据库连接可用,应用程序就会自动恢复运行.

至于重现测试问题,将以下两行添加到[mysqld]块下的my.ini或my.cnf文件中:

interactive_timeout=30
wait_timeout=30
Run Code Online (Sandbox Code Playgroud)

这是我命名为"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) { ....
Run Code Online (Sandbox Code Playgroud)


nfl*_*cco 3

这是我最终使用的,效果非常好。在偶尔连接丢失/重新启动时,它恢复得很好。我有一个 database.js 文件,它建立连接并定期检查它们。

提出请求:

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

这是我的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;
Run Code Online (Sandbox Code Playgroud)