重现 MySQL 错误:服务器关闭连接(node.js)
Posted
技术标签:
【中文标题】重现 MySQL 错误:服务器关闭连接(node.js)【英文标题】:Reproduce MySQL error: The server closed the connection (node.js) 【发布时间】:2012-10-12 15:56:06 【问题描述】:我正在尝试使用node mysql library 重现我在 EC2 上的 node.js 应用程序中看到的 MySQL 错误:
连接丢失:服务器关闭了连接。
我无法在本地重现该错误 - 我的代码可以很好地处理杀死数据库 - 它只是每隔几秒钟重新检查一次,并在重新启动后重新连接到数据库。在 EC2 上,它发生在太平洋时间凌晨 4 点左右,但数据库仍然正常运行。
我愿意
-
用我的本地 mysql 重现崩溃
在我的 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, 版本=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,跟踪=[列=13, 文件=/home/ec2-user/my-app/node_modules/mysql/lib/protocol/Protocol.js, 函数=Protocol.end, line=63, method=end, native=false, column=10, 文件=stream.js,函数=Socket.onend,行=80,方法=onend, native=false,column=20,file=events.js,function=Socket.emit, 行=88,方法=发射,本机=假,列=51,文件=net.js, 功能=TCP.onread,行=388,方法=onread,本机=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.emit (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;
;
【问题讨论】:
nodejs mysql Error: Connection lost The server closed the connection的可能重复 【参考方案1】:解决方案是使用池连接!
您可以编写代码来手动处理连接,它可以工作。 但是池是为此设计的,使用池连接解决了连接丢失错误。
var mysql = require('mysql');
var pool = mysql.createPool(
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
);
pool.query('SELECT 1 + 1 AS solution', function (error, results, fields)
if (error) throw error;
console.log('The solution is: ', results[0].solution);
);
pooling mysql connection
【讨论】:
【参考方案2】:查看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();
);
【讨论】:
是的,这似乎是最好的方法,并且您可以并行锤击您的数据库作为奖励。 最好将connection.end()
替换为connection.release()
,这样它就可以在不断开连接的情况下重复用于进一步的请求。【参考方案3】:
这是我最终使用的,效果很好。在偶尔的连接丢失/重新启动时,它恢复得很好。我有一个 database.js 文件,它建立连接并定期检查它们。
提出请求:
var conn = require('./database');
var sql = 'SELECT foo FROM bar;';
conn.query(sql, [userId, plugId], function (err, rows)
// logic
这是我的数据库.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;
【讨论】:
请告诉我配置文件中的queryTimeout和checkInterval要设置什么时间?【参考方案4】:我遇到了类似的问题,并创建了一个 getConnection() 包装函数,该函数在将 mysql 连接返回给调用者之前检查其健康状况并根据需要重新建立连接。在我的测试中,它为应用程序透明地处理了致命和非致命的连接问题。如果连接只是超时,应用程序会恢复而不会出现任何错误。如果存在暂时但致命的数据库连接问题,一旦数据库连接再次可用,应用程序将自动恢复运行。
至于重现问题进行测试,将以下两行添加到[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) ....
【讨论】:
【参考方案5】:使用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 点死去!
【讨论】:
不。我基本上在每个mysql查询上都设置了一个包装器来检查是否有连接,如果没有,则异步建立连接。我会把我的代码作为答案以上是关于重现 MySQL 错误:服务器关闭连接(node.js)的主要内容,如果未能解决你的问题,请参考以下文章
node.js ssh2 => 如何关闭连接并处理 ECONNRESET 错误
node-red node-red-contrib-mssql “连接错误:连接已关闭。”