【问题标题】:MongoDB Connections Spiking When Connecting from Node+Express从 Node+Express 连接时 MongoDB 连接激增
【发布时间】:2019-10-11 05:20:13
【问题描述】:

我正在尝试为我的移动应用创建一些 API。我正在使用 Node+Express+Mongo+Firebase。根据其他地方 (How to properly reuse connection to Mongodb across NodeJs application and modules) 的建议,我创建了以下代码结构:

这就是我的 mongoUtils.js 中的内容:

const MongoClient = require('mongodb').MongoClient
const uri = "mongodb+srv://user:password@blabla.azure.mongodb.net/bla?retryWrites=true&w=majority";

let _db

const connectDB = async (callback) => {
    try {
        MongoClient.connect(uri,{ useNewUrlParser: true }, (err, client) => {
            _db = client.db('ABC');
            return callback(err)
        })
    } catch (e) {
        throw e
    }
}

const getDB = () => _db
const disconnectDB = () => _db.close()
module.exports = { connectDB, getDB, disconnectDB }

这就是我在 index.js 中的内容:

const functions = require('firebase-functions');
const express = require('express');
const app = express();
var cors = require('cors');
app.use(cors());
const admin = require('firebase-admin');
const bodyParser = require('body-parser')
const assert = require('assert');

const MongoDB = require('./db/mongoUtils')

admin.initializeApp(functions.config().firebase);
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())

app.post('/getUserByPhone',(request,response)=>{

    MongoDB.connectDB(async (err) => {
        assert.equal(null, err);
        console.log("Connected correctly to server");
        const db = MongoDB.getDB();
        const collection = db.collection('users');
        console.log(request.body.phone);
        // Find some documents
        collection.find({/*Query here*/}).toArray(function(err, docs) {
            assert.equal(err, null);
            console.log("Found the following records");
            console.log(docs)
            response.send(docs);
        })
    })
})

app.post('/getUserById',(request,response)=>{
    var ObjectId = require('mongodb').ObjectId; 
    var id = request.body.userId;
    var userId = new ObjectId(id);

    MongoDB.connectDB(async (err) => {
        assert.equal(null, err);
        const db = MongoDB.getDB();
        console.log("Connected correctly to server");
        const collection = db.collection('users');
        collection.find({/*Query*/}).toArray(function(err, docs) {
            assert.equal(err, null);
            console.log("Found the following records");
            console.log(docs)
            response.send(docs);
        })
    })
})

app.post('/moreFunction',async(request,response)=>{
    var currTime = new Date();

    MongoDB.connectDB(async (err) => {
        assert.equal(null, err);
        const db = MongoDB.getDB();
        const collection = db.collection('coll_2');

        collection.find().toArray(function(err, docs) {
            assert.equal(err, null);
            response.send(docs);
        });
    })     
})

app.post('/anotherFunction',async(request,response)=>{
    MongoDB.connectDB(async (err) => {
        assert.equal(null, err);
        const db = MongoDB.getDB();
        console.log("Connected correctly to server");
        const collection = db.collection('coll_name');
        collection.find().toArray(function(err, docs) {
            assert.equal(err, null);
            response.send(docs);
        });
    })     
})

exports.api = functions.https.onRequest(app);

现在,每当我通过在我的 Android 设备上运行我的应用程序来测试它时,我都会在我的 MongoDb 控制台中看到连接高峰。当我在屏幕之间导航时,我看到应用程序使用了大约 25-30 个连接,而不是一个连接。我的方法有什么问题?为什么要使用这么多连接?

此应用未发布,我是唯一用户。

【问题讨论】:

  • 我相信您在这里使用 connectDB() --> 对于基本上创建新连接的每个请求,而不是重用连接。
  • 这就是本文推荐的内容:stackoverflow.com/questions/24621940/…。它说“这样做的原因是,在节点中,当模块被要求时,它们只会被加载/获取一次,所以你只会得到一个 _db 实例,而 mongoUtil.getDb() 将始终返回同一个实例。”
  • 只在应用程序级别连接到数据库一次,并在路由级别使用该连接。现在,在每条路线上,您都在建立新的连接。
  • @VikalpJain 但您没有在每个请求上调用 MongoDB.connectDB(async (err)) ,因此始终会创建新连接。您应该在 mongoUtil 类初始化中只连接一次 DB。在每个请求中,您应该只使用 MongoDB.getDB()
  • 感谢@Lucia 和 Sandor Bakos。我现在明白我犯的错误了。为了克服我尝试将我的 getDB 函数更改为: const getDB = async() => { try{ if (!_db){await connectDB()} return _db } catch (e) { throw e } } 而不是 ConnectDB,现在我从我的路由函数中调用 getDB。但这给出了“回调不是函数”错误。

标签: node.js mongodb firebase express google-cloud-functions


【解决方案1】:

这里有 async/await 和回调的奇怪组合,虽然我不会为你编写代码,但我可能会提供一些建议。

理想情况下,您将在需要调用 MongoDB 适配器之前进行一些初始化,这样您就不必等待先前解决的承诺(额外代码)或在每次获得时销毁并重新创建新连接请求(额外的代码并花费额外的时间进行 TLS 3 次握手)。在here之前,我已经写了一个重用连接和初始化代码的解决方案。

const MongoClient = require('mongodb').MongoClient
const uri = "mongodb+srv://user:password@blabla.azure.mongodb.net/bla?retryWrites=true&w=majority";

const client = new MongoClient(uri);
// client.connect returns a promise that can be awaited
const connectDB = () => client.connect();


const getDB = () => client.db;
// so does db.close
const disconnectDB = () => client.db.close();
module.exports = { connectDB, getDB, disconnectDB }

const MongoDB = require('./db/mongoUtils')

app.post('/getUserByPhone', async (request,response)=>{
    try {
      await MongoDB.connectDB();
      const db = MongDB.getDB();
      const collection = db.collection('users');
      const docs = await collection.find({/*Query here*/}).toArray();
      response.send(docs);
    } catch (e) {
      // handleErr(e);
      return response.send({ok: false}).status(500);
    }
})

【讨论】:

    【解决方案2】:

    我知道这是一个 nodejs 问题,但无论您选择哪种语言,下面的设计都会解决这个问题。

    无论您编写什么代码和使用哪种语言,如果您在每个脚本中创建新对象,即使在 MongoDB 端使用连接池,您也会看到一个峰值。我们有一个 Java 实现,我们看到了类似的峰值。在 Atlas 上,我们的连接池在 350 个最大连接中增加到 340 个,即使使用静态连接对象,以及所有最佳实践。

    你必须做的是在服务器启动时以某种方式创建 const MongoDB = require('./db/mongoUtils') 的 1 个对象,并将其存储在某处(在缓存/序列化..任何东西中)并确保它在整个应用程序中都可以访问。并通过一些通用函数/getter 强制所有 nodejs 类/脚本使用相同的对象。

    在 Java 中使用 ServletContext 存储一个连接对象后,我们发现我们的连接在 Atlas MongoDB 上一次被限制为最多 40-50 个。

    【讨论】:

      【解决方案3】:

      @EddieDean 的上述答案是一个很好的起点。我唯一建议的是更改以下内容:

      // client.connect() will only execute when client is not connected
      const connectDB = () => (!client.isConnected() ? client.connect() : client)
      

      这可以防止发生this 错误。

      【讨论】:

        猜你喜欢
        • 2023-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-20
        • 2016-12-24
        • 2017-04-30
        • 1970-01-01
        • 2018-11-12
        相关资源
        最近更新 更多