Mongoose连接池在每次调用新的Lambda时创建到Mongodb的连接

3gtaxfhh  于 2023-02-08  发布在  Go
关注(0)|答案(2)|浏览(175)

我们使用的是Mongoose、Nodejs、Serverless和AWS Lambda。为了使用同一个连接,而不是每次都打开和关闭连接,我创建了一个大小为10的连接池(对于我们现在的用例来说似乎已经足够了)。
但问题是,当我看到Lambda的Cloudwatch日志时,它与正在使用的连接并不相同。

  • 每次调用一个新的Lambda时,都会创建一个新的连接,而对该Lambda的后续调用使用第一次调用中打开的相同连接。*

导致一次打开的连接数量增加。在MongoDB Atlas上,我可以看到打开的连接数量非常多。
下面是我在没有缓存连接可用时创建连接的代码。如果缓存连接可用,将使用缓存连接,而不会创建新连接。

let cached_db;
exports.createConnection = async () => {
  if(cached_db == null){
    return await mongoose.connect(
    connection_uri,         
    { 'useUnifiedTopology': true , 
      'useNewUrlParser':  true, 
      'useFindAndModify': false , 
      'useCreateIndex': true,
      'socketTimeoutMS': 60000,
      'connectTimeoutMS': 60000,
      'poolSize': 10
    }
  ).then(conn => {
      cached_db = conn;
      return conn;
  }).catch((err) => {
      console.error('Something went wrong', err);
      throw err;
    });
  } else {
    console.log("Cached db in use.");
    return cached_db;
  }
}

相同的连接可以跨Lambda使用吗?有没有办法做到?

disbfnqx

disbfnqx1#

您应该在AWS Lambda处理函数之外定义MongoDB服务器的客户端。不要在每次调用函数时都定义一个新的MongoClient对象。这样做会导致驱动程序在每次函数调用时创建一个新的数据库连接。这可能会导致开销很大,并可能导致您的应用程序超出数据库连接限制。
或者,执行以下操作:
1.创建MongoClient对象一次。
1.存储该对象,以便您的函数可以跨函数调用重用MongoClient。

步骤1

将对MongoClient.connect()函数的调用隔离到它自己的模块中,这样连接就可以在函数之间重用,让我们为此创建一个文件mongo-client.js

    • 蒙戈客户. js**:
const { MongoClient } = require('mongodb');

// Export a module-scoped MongoClient promise. By doing this in a separate
// module, the client can be shared across functions.
const client = new MongoClient(process.env.MONGODB_URI);

module.exports = client.connect();

步骤2

导入新模块并在函数处理程序中使用它来连接到数据库。

    • 某个文件. js**:
const clientPromise = require('./mongodb-client');

// Handler
module.exports.handler = async function(event, context) {
  // Get the MongoClient by calling await on the connection promise. Because
  // this is a promise, it will only resolve once.
  const client = await clientPromise;
  
  // Use the connection to return the name of the connected database for example.
  return client.db().databaseName;
}

样本池大小

连接池大小是维护的数据库连接的高速缓存,以便将来需要对数据库发出请求时可以重用这些连接。连接池用于提高在数据库上执行命令的性能。

    • 注意:**maxPoolSizepoolSize是相同的,除了它们与您是否使用useUnifiedTopology: true设置有关。如果您使用useUnifiedTopology: truemaxPoolSize是规范兼容的设置,用于管理连接池的大小。但是如果您使用useUnifiedTopology: false(或省略它),poolSize是相同的,但在我们使用统一拓扑之前。
    • 注意:**每个连接消耗大约1MB RAM。
池大小的值

连接池是以mongod/mongos为基础的,因此当连接到一个3成员副本时,将有三个连接池(每个mongod一个),每个连接池都有一个maxPoolSize。此外,每个节点还需要一个监视连接,因此您最终会得到(maxPoolSize+1)*number_of_nodes TCP连接。
在我看来,如果你不关心CPU和RAM,你应该使用所有可用的连接(如果我们已经有了,为什么不呢?)

    • 例如:**您有一个包含3个副本集的Atlas可用群集,该群集最多支持500个连接,并且您只有一个应用程序连接到该群集,请将所有连接分配给该应用程序。为了设置poolSize的值,您可以使用以上连接计算:
poolSize = (maximum_connections/number_of_nodes) - 1

poolSize = (500/3) - 1

poolSize = 165

如果有2个应用程序将连接到同一个集群,请为每个应用程序分配一半的连接。
如果您的RAM内存有限,请检查您可以使用多少内存,并基于此计算poolSize(正如我在注解中所说的,您可以假设一个连接将消耗大约1MB的RAM)。
资源
有关详细信息,请查看this official MongoDB Docs
对于连接池,请选中thisthis

yiytaume

yiytaume2#

我从this blog中发现,如果恢复相同的快照,Lambda可能会使用相同的连接,如果生成新快照,Lambda可能会创建新连接。
所以如果我们在句柄函数之外使用,Lambda不能保证使用相同的连接。
所以在我看来,优化Mongodb连接数量的最佳方法是在lambda完成之前关闭连接,这样你的其他服务就可以使用免费连接。
使用以下方法在数据库交互完成后关闭连接。

createConnection.close()

相关问题