实施数据库查询以在 node.js 项目中读取和写入 MySQL 副本的正确方法?

Proper way of implementing the DB queries to read and write MySQL replicas in the node.js project?

我有一个 node.js express 项目,它使用 MySQL 5.6 数据库和 mysql 客户端连接到它。项目中没有 ORM,原始查询是针对数据库的 运行。现在,我需要以将 SELECT 查询(不在事务内)路由到 MySQL 只读副本的方式更改代码。由于我以前从未在任何其他项目上做过类似的事情,所以我想知道这样做的最佳实践是什么(在 node.js)。

我发现 sequelize 库有配置选项允许分别指定读写副本,然后不同的查询将被路由到不同的数据库,但我没有找到任何选项在 mysql 客户端库中进行。我尝试使用 sequelize,但似乎对于 RAW 查询不支持此功能。

除此之外,我想知道从架构的角度来看最好的解决方案是什么?目前,我看到的唯一选择是拥有一些具有 query 方法的数据库包装服务,反过来,封装 mysql connection.query 并基于提供的 sql它决定使用哪个数据库连接 - 读取或写入(除非它是一个事务 - 然后一切都应该在同一个数据库中完成,我猜)。这是一个相当愚蠢的解决方案,但这是我现在唯一的想法。

谁能分享一下这方面的经验?不仅在 node.js 个项目中 - 欢迎任何架构想法。也许有某种方法可以在请求到达主机之前代理请求?感谢您提前回答。

所以,最终,我以一种相当直接的方式解决了它:为读取和写入数据库副本创建了单独的连接池,并在我需要的地方直接使用它们中的每一个:

const writePool = mysql.createPool(writeConnectionString);
const readPool = mysql.createPool(readConnectionString);

function getWriteConnection() {
    return writePool.getConnection();
};

async function getReadConnection() {
    const connection = await readPool.getConnection();
    connection.isRead = true;
    const originalQuery = connection.query;
    connection.query = function (...args) {
        if(!isSelectQuery(args[0])) {
            throw new Error('Read connection cannot be used for the commands other than SELECT.');
        }

        return originalQuery.apply(this, args);
    };

    return connection;
};

// checking if query is SELECT
function isSelectQuery(query) {
    return query.replace(/\s+/mi, '').toLowerCase().startsWith('select');
}

// release function
function release(connection) {
    if(connection.isRead) {
        readPool.releaseConnection(connection)
    } else {
        writePool.releaseConnection(connection);
    }
};

然后在代码中:

const connection = await database.getReadConnection();
await connection.query('SELECT * FROM ...');
....
database.release(connection);

这远不是解决它的最优雅的方法,但它以最少的更改和后续错误相对快速地解决了我的问题。