【问题标题】:Concurrent Requests - Why's the database connection crashing the Node process并发请求 - 为什么数据库连接会导致 Node 进程崩溃
【发布时间】:2014-11-17 13:11:32
【问题描述】:

概述

我正在用 NodeJS 开发一个 MVC 应用程序。当应用程序首次加载时,会创建数据库对象(使用池)

var pool = mysql.createPool({connectionLimit: 150, host: __host, user: __user, password: __password, database: __database}) module.exports = pool

当收到请求时,会创建一个 Controller 对象,该对象会创建一个 Model 来执行操作。模型从池中获取连接,执行操作,然后将连接释放回池。

//router snippet router.get('/post_data', function(req, res){ router.setRequestAndResponse(req, res) var post_data = new Post_Data() post_data.processDataFromGet(router) }) //controller code snippet Post_Data_Controller.prototype.processDataFromGet = function(router){ var controller_obj = this var data_array = {} var req = router.req, res = router.res //retrieving data from request and passing to the data_array controller_obj.model.create(data_array, function(result){ var xml = xmlbuilder.create("response") if (result.code == "error"){ xml.e("code", "error") xml.e("message", result.error_message) }else if (result.code == "success"){ xml.e("code", "success") } controller_obj.sendResponse(router.res, xml, "xml") }) } Post_Data_Controller.prototype.sendResponse = function(res, response, type){ if (type == "json"){ res.set({"Content-Type": "application/json", "Content-Length": JSON.stringify(response).length}) res.send(response) }else{ /* Default type is XML */ res.set({"Content-Type": "application/xml", "Content-Length": response.end({pretty: true}).length}) res.send(response.end({pretty: true})) } } //Model snippet Post_Data.prototype.create = function(data_array, callback){ /* data validation */ var fail = false, error_data = {} if (fail) {callback({code: "fail", cause: error_data}); return;} //the next 2 lines do not throw an error when uncommented //callback({code: "fail", cause: "how's it going"}); //return; __db_pool.getConnection(function(err, db_conn){ // the next two lines throw an error for two or more requests coming in at the same time callback({code: "fail", cause: "how's it going"}); return; if (err) { callback({code: "error", error_message: err}); return;} callback({code: "fail", cause: "how's it going"}); return; db_conn.query("sql command", [data_array], function(err, result){ if (err){ callback({code: "error", error_message: err}); return;} if (result && result.length > 0){ //affiliate and listing exist data_array.listing_id = result[0].listings_id var data = [data_to_insert] db_conn.query("sql command here", data, function(err, result){ db_conn.release() if (err){ callback({code: "error", error_message: err}); return;} if (result && result.affectedRows > 0) { callback({code: "success", data: {data_to_be_returned}}) }else {callback({code: "error", error_message:"Error inserting data"}); return} }) }else{ callback({code: "fail", cause: "error to send back"})} }) }) }

问题

这些请求是 Web 服务请求。 如果我发送一个 GET 请求,则不会发生错误;但是,当我发送两个或更多并发请求时,我收到此错误:

/project_path/node_modules/mysql/lib/protocol/Parser.js:82 throw err; ^ Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (http.js:689:11) at ServerResponse.res.set.res.header (/project_path/node_modules/express/lib/response.js:549:10)

我将罪魁祸首追溯到上面粘贴的模型代码中的特定行。似乎由于某种原因,一旦模型从池中获得第二个请求的连接,它就会以某种方式干扰第一个请求。两个请求仍然将正确的数据插入数据库;但是,第二个和后续请求无法在不抛出错误的情况下发送响应。

我已经使用 GET、POST 和 PUT 内容类型执行了请求;只有 GET 会引发错误。即使有超过一千个并发请求,所有其他内容类型也不会引发任何错误。

这是 GET 请求的 Web 服务代码;除了内容类型更改和放入正文中的数据外,其他内容类型相同。

for(var i=0; i less than 5; i++){ sendAsGet() i++ } function sendAsGet(){ try{ var data = "?data_to_be_sent" var uri =url.parse("http://localhost:4000/post_data") var options = {hostname: uri.hostname, port: uri.port, method: "GET", path: uri.path + data, agent: false} request = (uri.protocol == "https")? https : http var req = request.request(options, function(res){ var result = "" console.log("STATUS: " + res.statusCode) console.log("HEADERS: " + JSON.stringify(res.headers)) res.setEncoding("utf8") res.setTimeout(50, null) res.on("data", function(chunk){ result += chunk }) res.on("end", function(){ console.log(result) }) }) req.end() }catch(err){ console.log(err.message) } }

我想知道两件事:

  • 为什么获取数据库连接会导致此问题?
  • 为什么它只发生在 GET 请求上而不是 POST 和 PUT 上?

到目前为止,Google 和以前的 SO 问题都无法提供帮助。
谢谢。

【问题讨论】:

    标签: node.js node-mysql


    【解决方案1】:

    您看到错误的原因是您将请求/响应实例放在路由器本身上。 不要那样做。 路由器对象是一个“静态”对象,它不是每个请求的东西。所以目前这就是正在发生的事情(按顺序):

    1. 请求 #1 进来并将 req/res 设置为 router 并启动异步 model.create()

    2. 同时,请求 #2 进入并覆盖 router 上的 req/res 并启动自己的异步 model.create()

    3. 调用请求#1 的model.create() 回调,将响应发送到请求#2 的套接字。

    4. 请求#2 的model.create() 回调被调用,它尝试向刚才响应的res 发送响应。尝试将标头写入已发送的响应会导致您看到的错误。

    【讨论】:

    • 天哪!你说的很对!我不敢相信我没有看到。这是否意味着存储请求数据的静态对象不好?
    • 您最好根据需要传递req 和/或res
    • 哦,是的;我绝对明白发生了什么。感谢您的回答。
    • 你有一个如何不这样做的例子吗?我是 Node 新手(和一般的 JS)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-28
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多