Next.js 和 MongoDB Atlas - 收到 "已超过配置限制的连接数80%" 警报。

7

我看到了很多有关MongoDB Atlas的警报的帖子和文章(“连接%的配置限制已超过80”),但是无法弄清在我的Next.js应用程序中如何解决它。

我在处理程序函数外创建了我的数据库连接。我使用了一个名为withDatabase.js的中间件:

const client = new MongoClient(process.env.MONGODB_URI, { 
    useNewUrlParser: true, 
    useUnifiedTopology: true 
});

const addDbToRequest = (handler, req, res) => {
    req.db = req.connection.db("MYDBNAME");
    return handler(req, res);
};

const withDatabase = handler => async (req, res) => {
    if (!client.isConnected()) {
        await client.connect();
    }
    req.connection = client;
    return addDbToRequest(handler, req, res);
};

export default withDatabase;

这个中间件包装了API端点处理程序。

现在,如果我在每个API处理程序完成时关闭连接,就像这样:

    const { connection } = req;
    if (connection) {
        connection.close();
    }

接着,我针对同一个API处理程序进行第二个请求时出现了错误:

MongoError: Topology is closed, please connect

如果我没有关闭连接,使用一段时间后就会收到如下邮件提醒:

“警告:您的数据库连接池已满,请检查并处理。"

Connections % of configured limit has gone above 80

如何在Next.js应用程序中与MongoDB Atlas合作的最佳实践是什么?

谢谢!


你好,你找到任何可行的解决方案了吗?因为接受的答案对于我完全相同的情况并没有起作用。 - Agent K
2个回答

8
连接应该被重用,原因如下:
  1. 在每个 API 请求中打开和关闭数据库连接较慢。
  2. 这几乎不可扩展。假设每个用户同时发出几个 API 请求,当应用程序获得更多用户时,您很快就会达到相同的连接限制。

如何在 Node.js web 应用程序中管理 MongoDB 连接?

2022 年更新:

import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
  throw new Error('Please add your Mongo URI to .env.local')
}

if (process.env.NODE_ENV === 'development') {
  // In development mode, use a global variable so that the value
  // is preserved across module reloads caused by HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  // In production mode, it's best to not use a global variable.
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise

2022 年之前

MongoClient 的默认配置中,每个连接池的最大连接数(poolSize)设置为 5。因此,如果您只运行一个应用实例并检查客户端是否已连接,那么在 MongoDB Atlas 中不应该看到超过 ~5 条连接。

if (!client.isConnected()) {
  await client.connect();
}

请注意,Next.js 在开发模式下(next dev)每次请求都会“重启”,这似乎会影响MongoClient的缓存并创建许多连接。然而,在生产模式下,您不应该遇到此问题。

所以问题在于开发模式,因为我没有关闭连接。 - user3343396
1
“Fast Refresh” 是怎么样的?在开发模式下,每次代码更改都会触发新的连接,这将很快达到 MongoDB Atlas 的限制。 - Se7enDays
在我了解到“poolSize”配置之前,这一点毫无意义。正如MongoDb指南所述,“poolSize:指定实例连接池的最大大小。” 因此,当您执行“client.connect()”时,这将设置一个连接'池'(可以由多个连接组成)。开发人员可能应该用不同的方式来措辞“connect”函数(比如说“ICP”,即实例连接池),以便用户不会认为它只是简单地建立到数据库的单个连接。MongoDb Atlas似乎没有跟踪连接池,只有连接。 - w. Patrick Gale
有人能提供一个使用NextJS和mongoose的示例吗? - josealvarez97
@josealvarez97 你找到任何可行的解决方案了吗?我迫切寻找同样的解决方法。 - Agent K

0
在Next的开发模式中解决最大连接数问题时,我发现将已重用/缓存的 client 对象写入全局Node对象可以使其在刷新之间保持不变。
const MongoClient = require('mongodb').MongoClient;

async function useMongoClient() {
  if (!this.client) {
    this.client = await MongoClient.connect(process.env.MONGODB_URI, {
      useUnifiedTopology: true,
    });
  }

  return this.client;
}

module.exports = useMongoClient;

在我的环境中,“this”出现未定义的情况,我无法将任何参数附加到它上面...“global”是一个东西,但我尝试创建“global.cachedDB”,它总是未定义。 - K.H. B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接