猫鼬超时与AWS DocumentDB交谈

问题描述

我们正在尝试在基于Serverless的Express构建的lambda中连接到AWS DocumentDB。为此,我们使用猫鼬和一个类似于

的连接函数
import mongoose from 'mongoose';
import logger from './utils/logger';
import fs from 'fs';

const READYSTATE_CONNECTED = 1;

const mongoDB = process.env.MONGODB_URI;

const certificateFilePath = __dirname + '/rds-combined-ca-bundle.pem';
logger.info(`Loading certificate file from ${certificateFilePath}`);
let ca = [fs.readFileSync(certificateFilePath)];


logger.info('Connection is ' + mongoose.connection.readyState);
if (mongoose.connection.readyState !== READYSTATE_CONNECTED) {
    logger.info(`Connecting to mongo using env connection string ${mongoDB}`);
    mongoose.connect(mongoDB,{ useNewUrlParser: true,useUnifiedTopology: true,checkServerIdentity: false,ssl: true,sslCA: ca }).catch((err) => {
        logger.error(`Unable to connect to mongoose due to ${err.reason}`);
        console.error(err);
    });
}
mongoose.Promise = global.Promise;
const db = mongoose.connection;

// eslint-disable-next-line no-console
db.on('error',console.error.bind(console,'MongoDB connection error:'));

export default db;

这里的想法是,我们维护一个连接并重用它,以避免为进入lambda的每个请求创建新连接的开销。在大多数情况下,这可以正常工作,但偶尔(也许一天两次)有时,我们会发现连接数据库的问题。似乎很可能会使Lambda崩溃,我们必须在Lambda上触发更改以欺骗Lambda重新启动我们的应用程序,然后所有其他操作又可以正常工作几个小时。我们在4个相同的环境中运行,似乎生产环境是唯一遇到此问题的环境。生产比其他环境要忙一些,但实际上只有50%。

错误看起来像

2020-11-09T20:10:36.565Z d88c9b33-6b84-44cd-8c1d-297c6334aad5 ERROR MongooseServerSelectionError: connection timed out
at NativeConnection.Connection.openUri (/var/task/node_modules/mongoose/lib/connection.js:800:32)
at /var/task/node_modules/mongoose/lib/index.js:342:10
at /var/task/node_modules/mongoose/lib/helpers/promiSEOrCallback.js:31:5
at new Promise (<anonymous>)
at promiSEOrCallback (/var/task/node_modules/mongoose/lib/helpers/promiSEOrCallback.js:30:10)
at Mongoose.connect (/var/task/node_modules/mongoose/lib/index.js:341:10)
at Object.<anonymous> (/var/task/src/mongoose.js:19:24)
at Module._compile (internal/modules/cjs/loader.js:1137:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
at Module.load (internal/modules/cjs/loader.js:985:32)
at Function.Module._load (internal/modules/cjs/loader.js:878:14)
at Module.require (internal/modules/cjs/loader.js:1025:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (/var/task/src/AppBuilder.js:17:1)
at Module._compile (internal/modules/cjs/loader.js:1137:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10) {
reason: TopologyDescription {
type: 'replicasetnoprimary',setName: 'rs0',maxSetVersion: null,maxElectionId: null,servers: Map {
'documentdbmasterinstance-xxxx.xxx.us-east-1.docdb.amazonaws.com:27017' => [ServerDescription],'documentdbreplica1instance-xxxx.xxxx.us-east-1.docdb.amazonaws.com:27017' => [ServerDescription],'documentdbreplica2instance-xxxx.xxxx.us-east-1.docdb.amazonaws.com:27017' => [ServerDescription]
},stale: false,compatible: true,compatibilityError: null,logicalSessionTimeoutMinutes: null,heartbeatFrequencyMS: 10000,localThresholdMS: 15,commonWireversion: 6
}

到目前为止,我们还无法确定导致此问题的任何特定操作。到那时,数据库的连接数确实有所增加,但仅增加到约75个,并且我们在r5.large上运行,应该允许1700个连接,所以我们远远超出了这个限制。

我不确定错误日志中是否提到replicasetnoprimary一个红色鲱鱼,但是在类似问题报告中似乎都没有提到。我对连接是否真的超时感到怀疑。没有一个lambda调用花费超过200毫秒的时间。

我想的问题是:

  • 连接代码中是否有明显的原因导致这种情况?
  • 在这个由lambda表示的快速应用程序中,有没有更好的,更规范的方法来建立和维护连接?
  • replicasetnoprimary是否表明documentdb选择新的主要数据库或该主要数据库无法访问有问题?
  • 有什么建议可以记录下来吗?

编辑: 我们的连接字符串看起来像

mongodb://redacted:redacted@prod-db.cluster-cvgzkbo26lzb.us-east-1.docdb.amazonaws.com:27017/database?ssl=true&ssl_ca_certs=rds-combined-ca-bundle.pem&replicaset=rs0&readPreference=secondaryPreferred&retryWrites=false

解决方法

连接超时可能有多种原因。最常见的原因是将您的IP地址列入白名单或启用公共访问,以便您可以访问数据库。

另一个原因可能是您使用的协议。有关更多信息,请共享连接字符串的格式,以便我可以相应地检查和更新答案。