【问题标题】:Vercel creates new DB connection for every requestVercel 为每个请求创建新的数据库连接
【发布时间】:2020-11-22 07:28:24
【问题描述】:

我正在开发一个新网站,虽然我们在本地开发时一切正常,但当我们尝试在 Vercel 上部署时遇到了问题。该应用程序对页面和 API 使用 Sapper 框架,以及我们通过 Mongoose 访问的 MongoDB Atlas 中的数据库。我们在本地的行为是我们npm run dev 并建立了一个单独的数据库连接,该连接一直持续到我们关闭应用程序为止。

当它被部署到 Vercel 时,建立数据库连接并打印“数据库连接成功”消息并且只应该运行一次的代码改为在每个 API 请求上运行

这似乎很快就失控了,达到了我们数据库的 500 个连接的限制:

因此,在网站被单个用户短暂使用后,我们的一些 API 请求开始失败并出现此错误(我们让数据库接受任何连接而不是 IP 白名单,因此错误给出的建议是'很有帮助):

我们的实现是在 .js 文件中调用mongoose.connect

mongoose.connect(DB, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useFindAndModify: false,
    useUnifiedTopology: true
}).then(() => console.log("DB connection successful!")).catch(console.error);

然后我们 import Sapper 的 server.js 中的那个文件。我们能够找到的建议是“只缓存连接”,但这并没有成功,而且似乎更像是node-mongodb-native 的事情。无论如何,这是我们尝试过的,但在本地没有更好或更差,但也没有解决 Vercel 上的问题:

let cachedDb = {};

exports.connection = async () => {
    if (cachedDb.isConnected)
        return;
        try {
            const db = await mongoose.connect(DB, {
                            useNewUrlParser: true,
                            useCreateIndex: true,
                            useFindAndModify: false,
                            useUnifiedTopology: true
                        });
            cachedDb.isConnected = db.connections[0].readyState;
            console.log("DB connection successful!");
            return cachedDb;
        } catch(error) {console.log("Couldn't connect to DB", error);}

那么...有没有办法在不更换至少一个部件的情况下完成这项工作?该网站尚未上线,因此更换某些东西并不是世界末日,但“只需更改设置”绝对比从头开始更可取。

【问题讨论】:

  • 你在问太多移动的东西。如果您的框架不为您管理数据库连接,则它与为每个请求建立的连接无关。
  • 否则链接到您的框架中讨论数据库连接的文档。
  • 我认为这很好 - 感谢您发布它。
  • 我喜欢了解问题的背景,作为奖励,我了解了 Sapper。

标签: mongodb mongoose mongodb-atlas vercel sapper


【解决方案1】:

总结

Vercel 上的无服务器功能就像一个独立的进程一样工作。虽然可以“按函数”缓存连接,但将 serverful-ready 库部署到无服务器环境并不是一个好主意。以下是您需要回答的几个问题:

  • 您的框架或数据库库是否在缓存连接?
  • 您的代码是否为 Serverless 做好了准备?
  • Vercel 针对什么类型的工作负载进行了优化?

进一步的背景

Vercel 是一个出色的前端平台,可以使用无服务器函数作为助手。与工作流结合使用的 CDN 使部署过程非常快速,并允许您更快地移动。部署成熟的 API 或服务式工作负载绝不是一个好主意。假设我需要将 MySQL 与 Vercel 一起使用。而不是mysql,您应该使用mysql-serverless,它针对无服务器原语进行了优化。即使考虑到这一点,根据您期望的请求级别,仅将 VM/Container 用于 API 可能会更便宜。因此,我们最终会得到以下理想的解决方案:

Frontend (Vercel - Serverless) --> Backend (Serverful - External provider) --> DB

免责声明:目前,我为 Vercel 工作。

【讨论】:

    【解决方案2】:

    NextJS 提供的示例代码说要缓存数据库连接,但这也是我自己遇到的问题。

    两者都在这里 https://github.com/vercel/next.js/blob/canary/examples/with-mongodb-mongoose/utils/dbConnect.js

    这里 https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js

    正在缓存连接,如果我复制示例,我会遇到与 OP 相同的问题。

    这里也说 https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

    我可以直接与我的数据库交互。一方面我被告知要缓存连接的信息相互矛盾,而团队成员告诉我它不适合这种方法,尽管文档和示例告诉我其他情况。这是错误报告类型的情况吗?

    【讨论】:

      【解决方案3】:

      我正在努力解决类似的问题,但我在这里遇到了一个示例: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/util/mongodb.js

      显然诀窍是使用global 变量:

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

      【讨论】:

      • 我尝试了这种方法但没有成功,抱怨它找不到未定义的 mongo(全局不存在吗??gasp)这使我得出结论 vercel 没有'在其容器中没有全局对象....我最终剥离了 vercel 在这里给出的基本示例:vercel.com/guides/…
      • 它对我有用。你所指的那个曾经时不时地撞到我身上。多么奇怪的事情。奇怪的是,它们提供了两种不同的方法,其中一种隐藏在 git repo 中。
      • @JakubPelák 是否在您的开发环境或 Vercel 上为您解决了这个问题?
      • @rnbrady 我猜两者都有。但我在 localhost 上没有这个问题。
      • 我觉得效果不太好.....是不是只为next.js设计的?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 1970-01-01
      • 2014-01-23
      相关资源
      最近更新 更多