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

NodeJS应用在MySQL主从故障切换后无法更新数据库连接

问题根源与解决方案

你的问题确实是Node.js的DNS缓存机制导致的。Node.js默认会缓存DNS解析结果,且默认缓存时长较长(TTL由DNS服务器返回,但Node.js不会主动刷新)。当集群主节点切换后,虽然域名已指向新主,但未重启的Node.js进程仍会使用缓存的旧IP连接只读的旧主节点,从而触发写操作错误。

以下是几种可行的解决方案:

1. 连接池层面的实时校验(推荐生产环境使用)

利用mysql包的连接池配置,在每次获取连接前校验节点是否可写,若检测到只读则丢弃旧连接,强制重新建立新连接(此时会重新解析DNS获取新主IP):

const mysql = require('mysql');

const poolConfig = {
  host: '你的集群域名',
  user: '数据库账号',
  password: '数据库密码',
  database: '目标库',
  connectionLimit: 10,
  testOnBorrow: true, // 从连接池取连接前执行校验
  acquireTimeout: 3000,
  // 自定义校验逻辑
  validateConnection: function(conn) {
    return new Promise((resolve, reject) => {
      conn.query('SELECT @@global.read_only AS is_read_only', (err, rows) => {
        if (err) {
          reject(err);
          return;
        }
        // 如果节点是只读状态,拒绝使用该连接
        resolve(rows[0].is_read_only !== 1);
      });
    });
  }
};

const pool = mysql.createPool(poolConfig);

当校验发现连接指向的是只读节点时,连接池会自动丢弃该连接,重新创建新连接,此时会重新解析DNS拿到新主节点的IP。

2. 捕获只读错误时重置连接池

在应用中捕获"read only"错误,主动清空现有连接池并重新初始化,强制触发DNS重新解析:

// 监听连接池错误
pool.on('error', (err) => {
  if (err.message.includes('read only')) {
    // 关闭现有连接池
    pool.end(() => {
      // 重新初始化连接池
      pool = mysql.createPool(poolConfig);
    });
  }
});

// 或者在查询时捕获错误
function executeQuery(sql) {
  return new Promise((resolve, reject) => {
    pool.query(sql, (err, results) => {
      if (err && err.message.includes('read only')) {
        // 重置连接池并重试
        pool.end(() => {
          pool = mysql.createPool(poolConfig);
          pool.query(sql, (retryErr, retryResults) => {
            retryErr ? reject(retryErr) : resolve(retryResults);
          });
        });
      } else {
        err ? reject(err) : resolve(results);
      }
    });
  });
}

3. 临时禁用DNS缓存(应急方案)

启动Node.js应用时添加环境变量,强制禁用DNS缓存,每次请求都会重新解析域名:

NODE_DISABLEDNSCACHE=1 node your-app.js

⚠️ 注意:该方案会增加DNS查询开销,影响应用性能,仅建议作为临时应急手段,不适合长期生产环境使用。

4. 更换支持自动故障转移的客户端库

考虑切换到mysql2(mysql包的升级替代)或@mysql/xdevapi,这些库提供了更灵活的连接管理和故障转移支持,更容易实现动态地址切换逻辑。比如mysql2的连接池可以配合自定义的地址解析逻辑,定期刷新DNS结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:30:12