Vercel 为每个请求创建新的数据库连接

问题描述 投票:0回答:4

我正在开发一个新网站,尽管我们在本地开发时一切运行良好,但当我们尝试在 Vercel 上部署时遇到了问题。该应用程序的页面和 API 使用 Sapper 框架,以及我们通过 Mongoose 访问的 MongoDB Atlas 中的数据库。我们在本地的行为是,我们

npm run dev
建立了一个数据库连接,该连接一直持续到我们关闭应用程序为止。

Local logs

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

New DB connection per request

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

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

我们的实现是在 .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);}

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

mongodb mongoose mongodb-atlas vercel sapper
4个回答
9
投票

总结

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

  • 您的框架或数据库库是否缓存连接?
  • 您的代码准备好用于无服务器了吗?
  • Vercel 针对什么类型的工作负载进行了优化?

进一步的背景

Vercel 是一个优秀的前端平台,可以使用无服务器函数作为助手。部署成熟的 API 或服务器负载永远不是一个好主意。假设我需要将 MySQL 与 Vercel 结合使用。您应该使用 mysql-serverless,而不是 mysql,它针对此类环境的原语进行了优化。即使考虑到这一点,根据您期望的请求级别,仅使用 API 的虚拟机/容器可能会更便宜。因此,我们最终会得到以下理想的解决方案:

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

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


3
投票

如果您使用的是MongoDB Atlas的云数据库,那么您可以使用mongodb-data-api库,该库是基于MongoDB Atlas的Data API进行封装的。所有数据操作均通过HTTPS接口进行,不存在连接问题。

import { MongoDBDataAPI, Region } from 'mongodb-data-api'

const api = new MongoDBDataAPI({
  apiKey: '<your_mongodb_api_key>',
  appId: '<your_mongodb_app_id>'
})

api
  .findOne({
    dataSource: '<target_cluster_name>',
    database: '<target_database_name>',
    collection: '<target_collection_name>',
    filter: { name: 'Surmon' }
  })
  .then((result) => {
    console.log(result.document)
  })

1
投票

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

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


1
投票

我正在努力解决类似的问题,但我在这里遇到了一个例子:

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 }
}
© www.soinside.com 2019 - 2024. All rights reserved.