Mongoose在NextJS中创建太多连接

ejk8hzay  于 2023-10-19  发布在  Go
关注(0)|答案(1)|浏览(172)

我一直在使用Mongoose将Mongodb与我的nextjs应用程序连接起来,在开发模式下一切都很好,但当我部署项目时,即使是一个用户(我)也需要大约60到80个连接。当我与3/4的朋友分享链接时,连接已达到500个连接限制。
下面是我的initDB文件的代码:

import mongoose from "mongoose";

const MONGO_URI = process.env.MONGO_URI;

if (!MONGO_URI) {
  throw new Error("Error Code: grx30xd33d");
}

let cached = global.mongoose;
if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

async function initDB() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
      useNewUrlParser: true,
      useUnifiedTopology: true,
      maxPoolSize: 50,
      wtimeoutMS: 2500,
      useNewUrlParser: true,
    };

    mongoose.set("strictQuery", false);
    cached.promise = mongoose.connect(MONGO_URI, opts).then((mongoose) => {
      return mongoose;
    });
  }

  try {
    cached.conn = await cached.promise;
  } catch (e) {
    cached.promise = null;
    throw e;
  }

  return cached.conn;
}

export default initDB;

这是我使用initDB的页面。

import initDB from "../../../helpers/initDB";
import directorySchema from "../../../models/directory/directorySchema ";

export default async function handler(req, res) {
  await initDB();

  return new Promise(async (resolve, reject) => {
    try {
      const userProf = await directorySchema
        .find()
        .limit(20)
        .sort({ _id: -1 })
        .then(async (response) => {
          if (response !== null) {
            res.json({
              success: true,
              data: response,
              message: "Data Fetched Successfully",
            });
          } else {
            return res.json({
              success: false,
              message: "Invalid data response",
            });
          }
        })
        .catch((error) => {
          console.log(error);
          res.json(error);
          res.status(405).end();
          return reject();
        });
    } catch (error) {
      console.log(error);
    }
  });
}

响应工作正常,我得到了所需的响应,但在mongodb中达到了连接限制。
这是写这个问题时的连接截图。

aelbi1ox

aelbi1ox1#

**这个问题不是next.js的问题,而是Vercel主机的问题。**正如OP所指出的,这个问题在本地是不可重现的。

问题是Vercel的无服务器特性与厚状态mongodb客户端不太兼容。Mongodb原生nodejs驱动程序被设计为永久运行,管理套接字连接以将其重用于多个请求,跟踪副本集拓扑等。另一方面,Vercel在每个HTTP请求上启动一个新的nodejs进程,这使得无法重用已经打开的连接。
“来自可靠来源的答案”部分:
这个问题正在https://github.com/vercel/next.js/discussions/12229中讨论,在回答这个问题时仍然是开放的。
最实用的建议来自当前的next.js仓库维护者Lee罗宾逊,
您可以使用Mongo的Data API。
https://www.mongodb.com/docs/atlas/api/data-api-resources/
它确实解决了连接池的问题,成本是:

  • 性能指标:每个数据库请求都是HTTP调用,在简单的请求上慢100倍。
  • 维护:它需要保持外部数据API与vercel应用程序同步
  • 相关性:你不会使用本机驱动程序,因此你不能使用任何依赖于它的库-特别是在这个问题的上下文中。

贡献者克里斯·安东尼推荐了一种不那么戏剧性的方法:
1.确保连接被缓存,并且正确处理承诺的连接。- 参见下一个示例[https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js](https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js
1.确保您已将客户端配置为终止空闲连接。在不支持maxIdleTimeMS的情况下,socketTimeoutMS也可以。
1.确保关闭所有光标。以前,我让Mongo服务器做这个。但这很可悲现在,我确保首先存储响应,然后手动关闭每个端点上的光标。
例如,在池中有1个连接的配置:

const config = {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        maxPoolSize: 1,
        minPoolSize: 1,
        socketTimeoutMS: 10000,
        serverSelectionTimeoutMS: 10000,
        maxIdleTimeMS: 10000,
    };

将导致每个http请求1个连接,但驱动程序将无法并行运行请求。您需要尝试使用精确的超时和池大小来找到平衡。
这远远不能有效地使用驱动程序,但至少它将解锁依赖库的使用,如mongoose。
关闭连接有点棘手,如果你在所有查询承诺都被解析之前关闭连接,你会得到“MongoError:拓扑已关闭,请连接”错误。对于Mongoose来说尤其如此,因为它被设计为使用更高的抽象级别,并且不手动管理连接。

相关问题