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

我试图重现一个MySQL错误,我看到我的节点mysql库 EC2上的node.js应用程序:

连接丢失:服务器closures连接。

我无法在本地重现错误 – 杀死数据库被我的代码处理得很好 – 它只是每隔几秒重新检查一次,重新连接到数据库一旦重新启动。 在EC2上,它发生在凌晨4点左右,但数据库仍然运行良好。

我想

  1. 用我的本地mysql重现崩溃
  2. 在我的mysql helper模块中添加我需要的任何逻辑来处理这个问题

这是我的node.js应用程序中的错误:

2012-10-22T08:45:40.518Z – error: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,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 = [错误:连接丢失:服务器closures连接。
在Socket.onend(stream.js:80:10)上​​的Protocol.end(/home/ec2-user/my-app/node_modules/mysql/lib/protocol/Protocol.js:63:13)。发出(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; }; 

检查node-mysql中的 mysql池function

 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(); }); 

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

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

 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) { .... 

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

提出要求:

 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; 

使用通用池 ,我写了一些本地工作。 我想我会testing它,看看它是不是在服务器端奇怪的方式崩溃。

 // 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点死亡没有明显的原因!