Vercel 为每个请求创建新的数据库连接 [英] Vercel creates new DB connection for every request

查看:41
本文介绍了Vercel 为每个请求创建新的数据库连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm working on a new website, and although things were working well as we developed locally we've run into an issue when we tried to deploy on Vercel. The app uses the Sapper framework for both the pages and an API, and a database in MongoDB Atlas that we access through Mongoose. The behavior we have locally is that we npm run dev and a single DB connection is made which persists until we shut the app down.

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

When it gets deployed to Vercel though, the code which makes the DB connection and prints that "DB connection successful" message and is only supposed to run once is instead run on every API request

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

This seems to quickly get out of hand, reaching our database's limit of 500 connections:

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

As a result, after the website is used briefly even by a single user some of our API requests start failing with this error (We have the db accepting any connection rather than an IP whitelist, so the suggestion the error gives isn't helpful):

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

Our implementation is that we have a call to mongoose.connect in a .js file:

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

然后我们在 Sapper 的 server.jsimport 该文件.我们能够找到的建议是只缓存连接",但这并没有成功,而且似乎更像是 node-mongodb-native 的事情.无论如何,这就是我们尝试过的,在本地没有更好或更糟的效果,但也没有解决 Vercel 上的问题:

and then we import that file in Sapper's server.js. The recommendation we've been able to find is "just cache the connection", but that hasn't been successful and seems to be more of a node-mongodb-native thing. Regardless, this is what we tried which didn't work better or worse locally, but also didn't fix the problems on 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);}

那么……有没有办法在不更换至少一个零件的情况下使这项工作正常进行?该网站尚未上线,因此更换某些内容并不是世界末日,而是只需更改设置"即可.绝对优先于从头开始.

So... is there a way to make this work without replacing at least one of the pieces? The website isn't live yet so replacing something isn't the end of the world, but "just change a setting" is definitely preferred to starting from scratch.

推荐答案

总结

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

Summary

Serverless functions on Vercel work like a self-contained process. While it is possible to cache the connection "per function," it is not a good idea to deploy a serverful-ready library to a serverless environment. Here are a few questions that you need to answer:

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

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

Vercel is an excellent platform for your frontend that would use Serverless Functions as helpers. The CDN available in conjunction with the workflow makes the deployment process very quick and allows you to move faster. Deploying a full-blown API or serverful workload will never be a good idea. Let's suppose I need to use MySQL with Vercel. Instead of mysql, you should use mysql-serverless, which is optimized for the serverless primitives. Even with that in mind, it will be probably cheaper to just use a VM/Container for the API depending on the level of requests you are expecting. Therefore, we would end up with the following ideal solution:

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

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

这篇关于Vercel 为每个请求创建新的数据库连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆