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

Vercel与Mongo Atlas连接数超限问题求助

解决Next.js+Mongoose连接Mongo Atlas超限问题

针对你遇到的100用户同时访问触发M10实例1500连接上限、每次请求创建新连接且持续数分钟的问题,结合你的代码和Serverless场景,给出以下实用解决方案:

1. 配置Mongoose连接池(核心修复)

你的Mongoose配置中options为空,未启用连接池复用,这是每次请求新建连接的关键原因。Serverless环境下必须配置合理的连接池参数,让连接在函数实例内复用,避免频繁创建新连接。

修改mongoose.ts的配置:

// mongoose.ts - Lib mongoose
import mongoose, { Mongoose } from "mongoose";

const MONGODB_URI = process.env.MONGODB_URI as string;

// 配置连接池参数
const options = {
  maxPoolSize: 10, // 每个函数实例的最大连接数,根据实例规格调整
  minPoolSize: 2, // 保持的最小空闲连接数
  maxIdleTimeMS: 30000, // 闲置连接30秒后回收,避免长时间占用配额
  connectTimeoutMS: 10000, // 连接超时时间
  socketTimeoutMS: 45000, // Socket超时时间
};

class Singleton {
  private static _instance: Singleton;
  private clientPromise: Promise<Mongoose>;
  private constructor() {
    this.clientPromise = mongoose.connect(MONGODB_URI, options).then((mongoose) => {
      console.log("Mongoose connection created, pool size:", mongoose.connection.client.options.maxPoolSize);
      return mongoose;
    });
  }

  public static get instance() {
    if (!this._instance) {
      this._instance = new Singleton();
    }
    return this._instance.clientPromise;
  }
}
const clientPromise = Singleton.instance;

export default clientPromise;
  • maxPoolSize:控制每个函数实例的最大连接数,M10总连接数1500,假设最多有100个函数实例,设为10刚好不超限(100*10=1000 <1500),可根据实际并发调整。
  • maxIdleTimeMS:让闲置连接及时回收,避免连接长时间占用Atlas的连接配额。

2. 合并前端接口调用(减少函数触发次数)

首页发起7次带不同参数的同一Serverless函数调用,会导致7倍的函数执行和连接请求。将这些请求合并为一个接口,后端一次性处理所有查询并返回数据,直接减少连接消耗。

前端修改示例:

// 原代码:7次独立请求
// Promise.all([
//   fetch('/api/live?param=1'),
//   fetch('/api/live?param=2'),
//   ...
// ])

// 修改后:一次请求传递所有参数
fetch('/api/live/batch?params=1,2,3,4,5,6,7')
  .then(res => res.json())
  .then(data => {
    // 处理批量返回的结果
  })

后端修改示例(新增/api/live/batch):

// /api/live/batch.ts
import clientPromise from "@/database/mongoose";
import User from "@/models/User";
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "GET") {
    res.status(404).end();
    return;
  }

  await clientPromise;
  const params = req.query.params?.toString().split(',') || [];
  
  // 批量处理查询,比如根据不同param获取对应count
  const results = await Promise.all(
    params.map(param => User.find({ isLive: true, [param]: true }).count())
  );

  res.status(200).json({ results });
}

3. 验证单例连接是否生效

Serverless环境下,Next.js的API路由模块会在同一个函数实例内复用,你的单例模式应该能保证每个函数实例只创建一个连接池。可以在连接成功后打印连接ID,验证是否复用:

// 在mongoose.ts的then回调中添加
console.log("Connection ID:", mongoose.connection.id);

如果同一函数实例的多次请求打印相同的Connection ID,说明单例生效;如果每次都不同,检查是否模块被重复加载(比如路径别名配置问题)。

4. 监控连接数排查问题

在Mongo Atlas控制台的Database -> Connect -> Connection Pool页面,实时查看连接数的来源和状态,确认:

  • 连接数是否来自你的Serverless函数IP
  • 连接池的复用率是否提升
  • 闲置连接是否按时回收

额外建议

  • 如果使用Vercel等Serverless平台,可调整函数的并发限制,避免过多函数实例同时创建连接池。
  • 避免在API路由中重复初始化模型,确保模型在连接成功后统一注册。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:22:37