我正在开发一个涉及连接到多个 MongoDB 数据库(每个数据库包含大约 300 万用户)的项目。我并行连接到所有这些数据库并在这些数据库中执行搜索。然而,我觉得这个过程比预期的要慢。下面是我写的代码。
config.js(包含数据库的 URL)
export const dbURLs = [
// TODO: Refactor this approach
// Each URL has 3 million of Users
process.env.DATABASE_URL_1,
process.env.DATABASE_URL_2,
process.env.DATABASE_URL_3,
process.env.DATABASE_URL_4,
process.env.DATABASE_URL_5,
process.env.DATABASE_URL_6,
process.env.DATABASE_URL_7,
process.env.DATABASE_URL_8,
process.env.DATABASE_URL_9,
process.env.DATABASE_URL_10,
process.env.DATABASE_URL_11,
process.env.DATABASE_URL_12,
process.env.DATABASE_URL_13,
process.env.DATABASE_URL_14,
process.env.DATABASE_URL_15,
process.env.DATABASE_URL_16,
process.env.DATABASE_URL_17,
process.env.DATABASE_URL_18,
];
db.js(并行建立与所有数据库的连接)
async function connectToDatabases() {
const databases = [];
// Connecting in parallel
await Promise.all(
dbURLs.map(async (url, index) => {
try {
const client = new MongoClient(url, {
maxPoolSize: 19,
minPoolSize: 1,
});
await client.connect();
const db = client.db(dbName);
databases.push(db);
console.log(`Successfully connected: ${index}`);
} catch (error) {
console.error(`Failed to connect to database at ${index}: ${error.message}`);
}
})
);
return databases;
}
searchController.js(在所有数据库中搜索特定用户)
const databases = await connectToDatabases();
let accountFound = false;
let accounts = [];
for (const db of databases) {
const collection = db.collection(collectionName);
const account = await collection.find({ id: facebook_id }).toArray();
if (account.length > 0) {
accountFound = true;
accounts.push(...account);
break;
}
}
// other code
是否有更有效的方法来处理这些数据库之间的连接和搜索?
如何减少连接和查询数据库的时间?
首先,您必须考虑为同一类型的数据拥有多个数据库。也许决定将单个数据库拆分为多个数据库,以便在不同的机器上分发数据。如果是这样,我可以给出一条考虑 MongoDB 分片功能的建议:https://www.mongodb.com/docs/manual/sharding/
第二,我坚持将连接初始化移至应用程序的初始化阶段,而不是在请求时执行连接。这样您就可以在请求时使用连接,而无需花费宝贵的时间进行初始化。另外,这样您就可以消除“内存泄漏”,因为一旦创建连接,它将被保留直到被释放,因此最佳实践是在启动时保留连接并在应用程序关闭时释放它们。否则,每个请求都会保留越来越多的连接,直到达到其限制:https://www.mongodb.com/docs/manual/reference/limits/
下一步,确保您的集合(在您使用的每个数据库中)都有 id 字段的索引。相反,它会导致巨大的性能问题。从单字段索引开始:https://www.mongodb.com/docs/manual/core/indexes/index-types/index-single/#std-label-indexes-single-field
下一步,考虑分页。我明白了,您使用 .toArray
方法立即通过网络从数据库中获取
all文档。如果这就是您所需要的,如果您的文档包含更多数据,我可以建议添加一些投影(https://www.mongodb.com/docs/manual/tutorial/project-fields-from-query-results/)它是必需的,以便您可以减少通过网络传输的字节量。 最后
,您的代码不执行并行搜索。此外,一旦你的代码找到至少一个用户,你的代码就会停止搜索——这是故意的吗?如果没有,您可以通过以下方式显着提高性能(并使代码更小):
const cursors = databases.map((db) => {
const collection = db.collection(collectionName);
return collection.find({ id: facebook_id }).toArray();
});
const accounts = await Promise.all(cursors);
cursors.forEach((cursor) => cursor.close());
请注意,根据文档(https://www.mongodb.com/docs/drivers/node/current/fundamentals/crud/read-operations/cursor/#close),您必须关闭您的游标以避免内存和网络泄漏