You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sequelize的Node.js应用MySQL连接长期处于CLEANED UP状态原因排查

问题分析:Sequelize连接池长期持有CLEANED UP状态连接

我开发了一个使用Sequelize ORM连接MySQL的Node.js应用,其Sequelize配置文件如下:

const Sequelize = require("sequelize");
const moment = require('moment');
const sequelize = new Sequelize("test", "root", "", {
  host: "127.0.0.1",
  port: 3309,
  dialect: "mysql",
  dialectOptions: {
    connectTimeout: 30000
  },
  pool: {
    max: 100,
    min: 0,
    acquire: 60000,
    idle: 10000,
    evict: 600000, // Time interval to check for idle connections to evict in milliseconds (optional)
    maxIdleTime: 30000,
  },
  logging: (query, timing) => {
    const timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
    console.log(`[${timestamp}] SQL Query: ${query} Elapsed Time: ${timing} ms`);
  },
  benchmark: true,
});

sequelize
  .authenticate()
  .then(() => {
    console.log("Connection has been established successfully.");
  })
  .catch((err) => {
    console.error("Unable to connect to the database:", err);
  });

module.exports = sequelize;

应用中同时使用Promise和Async/Await,以下是异步事务示例代码:

try {
  (async () => {
    const t = await sequelize.transaction();
    try {
      const updateUser = await User.update(
        {
          update_column: "s",
        },
        {
          where: {
            username: "sadisha",
          },
          transaction: t,
        },
      );
      //some condition
      if (some_condition) {
        throw new Error("User account update failed");
      }
      await t.commit();
      return {
        status: true,
      };
    } catch (Exception) {
      console.log(Exception);
      await t.rollback();
      return {
        status: false,
      };
    }
  })()
    .then((responseFromAsync) => {
      if (responseFromAsync.status) {
        //do something
      } else {
        //do something
      }
    })
    .catch((error) => {
      console.log(error);
    });
} catch (Exception) {
  console.log(Exception);
}

经观察,在请求高峰时段,Node.js会长期持有处于CLEANED UP状态的数据库连接(最长可达8小时),通过show processlist可查看该状态;低请求量时无此现象,重启应用后这些连接才会释放。目前已尝试为MySQL数据库添加索引、优化查询语句、调整Sequelize配置(如上所示),但问题仍未解决,请问该现象的成因是什么?


成因分析

  • 事务连接未正确归还:你的事务代码存在嵌套异步结构问题,外层try/catch无法捕获自执行异步函数内部的异步异常。尽管内部处理了commit/rollback,但如果rollback操作本身抛出异常(比如网络中断),会导致连接无法被归还到连接池;另外,未处理的Promise拒绝也会造成连接资源泄漏,高并发下这类问题会被放大。
  • 连接池驱逐机制失效:你配置了maxIdleTime: 30000(连接最大空闲30秒)和evict: 600000(每10分钟检查一次空闲连接),但Sequelize依赖的generic-pool在高并发场景下,可能出现连接池内部状态同步延迟,导致已标记为CLEANED UP的连接没有被及时驱逐。同时min: 0的配置在低负载时能释放连接,但高峰时创建的大量连接,若驱逐逻辑未触发,会被长期持有。
  • 连接状态感知不一致:CLEANED UP是MySQL端标记的连接状态,但Sequelize连接池并未及时感知到该状态变化。高峰时大量连接被创建,部分连接因MySQL端超时、异常被标记为无效,但Sequelize仍将其视为可用连接保留在池中,导致无效连接长期占用资源。
  • 异步代码逻辑缺陷:自执行异步函数的Promise链与外层try/catch相互独立,外层无法捕获内部的异步错误,一旦出现未处理的异常,会导致连接资源无法正常释放,尤其是高并发场景下,这类泄漏会快速积累。

内容的提问来源于stack exchange,提问作者sadeee nadeee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 02:13:25