You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Vercel+Next.js时MongoDB连接数激增问题求助

MongoDB连接数暴涨问题排查与解决

问题背景

我使用Vercel搭配Next.js开发项目,客户端调用标准Next.js API路由。但单个用户访问时,MongoDB连接数就会增加50+,测试环境仅我一人使用,却常出现200+的数据库连接数。需要限制连接数或阻止其快速增长。

现有代码示例

API调用逻辑

export const deletePost = async ({ userId, postId }: { userId: string; postId: string }) => { 
  await connectMongoose(); 
  await PostModel.deleteOne({ _id: postId, userId }); 
};
export const getDrafts = async ({ userId }: { userId: string }) => { 
  await connectMongoose(); 
  const drafts = await DraftPostModel.find({ userId }).sort({ updatedAt: -1 }); 
  return drafts ? drafts.map((draft) => draft.toJSON()) : []; 
};

服务端渲染(SSR)

export const getServerSideProps: GetServerSideProps = async (context) => { 
  const id = await getOptionalAuthUserId(context); 
  const { query: { draftId } } = context; 
  const [privateUserData, draft] = await Promise.all([ 
    getPrivateUserData(id), 
    getDraft({ userId: id!, draftId: draftId as string }) 
  ]); 
  return { props: { draft, privateUserData } }; 
};

静态生成(SSG)

export const getStaticProps: GetStaticProps = async () => { 
  const [post] = await Promise.all([getSinglePost({ postId: POST_ID })]); 
  if (!post) { 
    return { notFound: true }; 
  } 
  return { props: { post }, revalidate: DEFAULT_REVALIDATION_TIME_IN_SECONDS }; 
};

Mongoose连接逻辑

import { ConnectionStates, connect } from "mongoose"; 
import { MONGODB_URI } from "@/utils"; 

if (!MONGODB_URI) { 
  throw new Error("Please define the MONGODB_URI environment variable inside .env.local"); 
} 

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

export async function connectMongoose() { 
  if (cached.connection && cached.connection.readyState === ConnectionStates.connected) { 
    return cached.connection; 
  } 
  if (!cached.promise || cached.connection.readyState !== ConnectionStates.connecting) { 
    cached.promise = connect(MONGODB_URI!, { 
      maxIdleTimeMS: 10000, 
      serverSelectionTimeoutMS: 15000, 
      socketTimeoutMS: 10000, 
      connectTimeoutMS: 10000, 
      maxPoolSize: 10 
    }); 
    cached.connection = await cached.promise; 
  } 
  return cached.connection; 
}

连接数情况

  • 初始连接数:数值较低
  • 部署浏览后:连接数大幅增长至200+

问题分析

  1. 连接缓存逻辑存在bug:当cached.connection为null时,访问cached.connection.readyState会抛出TypeError,导致多个并发调用重复创建连接请求,最终生成多个连接池。
  2. Vercel无服务器架构特性:每个API路由、SSR请求会启动独立的Lambda实例,每个实例拥有独立的global对象,因此每个实例都会创建自己的连接池。若maxPoolSize设为10,20个实例就会产生200+连接数。
  3. 连接池配置不合理:当前maxPoolSize设置过大,无服务器环境下单个Lambda实例处理请求量有限,不需要大连接池;闲置连接回收时间可能过长,导致连接未及时释放。

解决方案

1. 修复连接缓存逻辑

修改connectMongoose函数,避免空值访问错误,确保仅创建一个连接请求:

import { connect } from "mongoose"; 
import { MONGODB_URI } from "@/utils"; 

if (!MONGODB_URI) { 
  throw new Error("Please define the MONGODB_URI environment variable inside .env.local"); 
} 

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

export async function connectMongoose() { 
  // 已连接则直接返回
  if (cached.conn) { 
    return cached.conn; 
  } 

  // 无连接请求时创建唯一请求
  if (!cached.promise) { 
    const opts = { 
      maxIdleTimeMS: 5000, // 缩短闲置连接回收时间
      serverSelectionTimeoutMS: 15000, 
      socketTimeoutMS: 10000, 
      connectTimeoutMS: 10000, 
      maxPoolSize: 2, // 大幅降低单实例连接池大小
      minPoolSize: 0 // 无请求时释放所有闲置连接
    }; 

    cached.promise = connect(MONGODB_URI!, opts).then((conn) => { 
      cached.conn = conn; 
      return conn; 
    }); 
  } 

  // 等待连接完成并返回
  cached.conn = await cached.promise; 
  return cached.conn; 
}

2. 优化连接池配置

  • maxPoolSize:设为2-3,适配无服务器环境单实例低并发场景。
  • minPoolSize:设为0,让连接池在无请求时自动释放所有闲置连接。
  • maxIdleTimeMS:缩短至5000ms,加速闲置连接回收。

3. 调整Vercel函数配置

在vercel.json中设置函数超时时间,让闲置Lambda实例更快被回收:

{
  "functions": {
    "api/**/*.ts": {
      "timeout": 10
    },
    "pages/**/*.tsx": {
      "timeout": 10
    }
  }
}

4. 排查未释放的连接

  • 确保所有数据库操作都已正确使用await,避免未完成的请求占用连接。
  • 启用Mongoose debug模式,查看连接创建/释放日志:
    import mongoose from "mongoose";
    mongoose.set("debug", true);
    

5. 监控连接来源

通过MongoDB Atlas的连接监控功能,确认连接是否来自多个Vercel Lambda实例,验证上述分析。

内容的提问来源于stack exchange,提问作者user2634633

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:52:56