首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB地图集和AWS之间的间歇超时问题

问MongoDB地图集和AWS之间的间歇超时问题
EN

Stack Overflow用户
提问于 2019-12-16 10:36:14
回答 1查看 893关注 0票数 7

我在这个问题上有点绝望:我们运行Atlas是为了我们的API,该API与MongoDB集群在MongoDB Atlas (M20)上进行对话。为了防止在每个Lambda调用上创建一个新的连接,我们遵循这样的模式:https://docs.atlas.mongodb.com/best-practices-connecting-to-aws-lambda/在Lambda容器的生存期内缓存连接。我们有一个轻微的变化:

代码语言:javascript
复制
async function getProdDB() {
  const url = `mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASSWORD}@xxxxx-yyyy.zzzzz.net?retryWrites=true`

  if (!cachedDb || !cachedDb.serverConfig.isConnected()) {
    cachedClient = await MongoClient.connect(
      url,
      { useNewUrlParser: true, useUnifiedTopology: true }
    )
    cachedDb = cachedClient.db(process.env.DB_NAME)
  }

  return cachedDb
}

这也会检查我们是否相连。现在,98%的情况下,这是可行的,但我们的Lambda调用不时超时。我们试着诊断一下:

  1. 我们将Lambda的超时限制从6秒更改为30秒/60秒,而Lambda函数仍会不时超时。Mongo从未抛出错误,由于TimeoutError,总是Lambda完成了调用
  2. 如果成功调用和未成功调用,cachedDB.serverConfig.isConnected()返回rue`‘
  3. 导致超时的部分业务逻辑是对MongoDB本身的查询,在非常小的集合(最多100个文档)上,常见的MongoDB操作(如findOne或updateOne )。
  4. 我们尝试将NodeJS上的NodeJS驱动程序从3.3.1升级到3.3.5,遵循https://github.com/Automattic/mongoose/issues/8180 (不过,我们不是在使用猫鼬,只是官方的MongoDB NodeJS驱动程序),问题仍然存在。
  5. 我们尝试通过使用相同版本的驱动程序的MongoDB脚本直接查询我们的NodeJS集群,在几千个查询中,没有出现一个超时问题。所以我们得出结论,问题不是我们的集群本身,而是连接。
  6. 经常被调用的函数不会比经常被调用的函数更频繁地超时,但不太频繁。看来,尽管在调用MongoDB时返回true,并且在没有调用的情况下Lambda容器保持打开一段时间后无法重用,但我们与isConnected()的缓存连接似乎变得陈旧了。我们使用的是默认超时:https://scalegrid.io/blog/understanding-mongodb-client-timeout-options/
  7. 检查了阿特拉斯上的MongoDB日志条目-没有可疑
  8. 停止数据库连接解决了问题,但使大多数API调用速度慢了2-3倍,我们仍然希望了解问题的根源。

有没有人面临类似的问题,或者建议我们如何有效地调试这个问题?

EN

回答 1

Stack Overflow用户

发布于 2022-01-22 17:37:11

我们公司目前正在使用相同的体系结构(Lambda -> MongoDB Atlas集群)和500多个lambdas,我们没有看到连接超时的任何问题。我们使用的是3.6版的Node.js驱动程序。

下面是我们使用的代码:

代码语言:javascript
复制
public static async connect(url?: string): Promise<Db> {
    /** If MongoDB is already connected, return that */
    if (this.cachedDb && this.client && this.client.isConnected())
      return Promise.resolve(this.cachedDb);

    /** Check for MongoURL in env if not provided */
    const mongoUrl: string = url || process.env.MONGO_CONNECTION_URL || '';

    this.client = await MongoClient.connect(mongoUrl, {
      useUnifiedTopology: true,
      useNewUrlParser: true,
      ignoreUndefined: true,
    });

    this.cachedDb = this.client.db();

    return Promise.resolve(this.cachedDb);
  }

然后,我们在同一个MongoClient上使用缓存的db和客户机。

代码语言:javascript
复制
/**
 * MongoDB Client Class
 */
class MongoDbClient {
  private static cachedDb: Db | null = null;
  private static client: MongoClient | null = null;

  /**
   * Connects to a MongoDB database instance
   *
   * @param url The MongoDB connection string
   *
   * @returns An instance of a MongoDB database
   */
  public static async connect(url?: string): Promise<Db> {
    /** If MongoDB is already connected, return that */
    if (this.cachedDb && this.client && this.client.isConnected())
      return Promise.resolve(this.cachedDb);

    /** Check for MongoURL in env if not provided */
    const mongoUrl: string = url || process.env.MONGO_CONNECTION_URL || '';

    this.client = await MongoClient.connect(mongoUrl, {
      useUnifiedTopology: true,
      useNewUrlParser: true,
      ignoreUndefined: true,
    });

    this.cachedDb = this.client.db();

    return Promise.resolve(this.cachedDb);
  }

  /**
   * Retrieves the first document that matches a filter condition
   *
   * @param collectionName The name of the collection to search
   * @param filter The filter to search for
   * @param options MongoDB find one option to include
   *
   * @returns The first document that matches the filter condition
   */
  public static async findOne<T>(
    collectionName: string,
    filter: FilterQuery<T> = {},
    options: FindOneOptions<T extends T ? T : T> = defaultDocumentOptions
  ): Promise<T | null> {
    const db = await this.connect();
    return db.collection<T>(collectionName).findOne<T>(filter, options);
  }
}

我注意到的不同之处在于,我们正在检查MongoClient是否与Db连接。从那以后,驱动程序在使用以下代码的版本的内部处理中就不再推荐和使用它了:

代码语言:javascript
复制
// If a connection already been established, we can terminate early
  if (mongoClient.topology && mongoClient.topology.isConnected()) {
    return callback(undefined, mongoClient);
  }

另一件可能发生的事情是,Lambda偶尔会被破坏/破坏。这是不可预防的和Lambda的正常行为,这就是为什么AWS建议采用重试策略内置到您的程序中。

请注意,即使是AWS也有一个针对其文档的重试策略:

客户端(如AWS和AWS )对客户端超时、节流错误(429)和其他错误进行重试,这些错误不是由错误的请求引起的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59354857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档