当前位置: 首页 > 知识库问答 >
问题:

MongoDB Atlas 和 AWS Lambda 之间的间歇性超时问题

姜飞飙
2023-03-14

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

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调用时不时会超时。我们试着诊断了一下:

    < li >我们将Lambda的超时限制从6s更改为30s/60s,Lambda函数仍会不时超时。Mongo从不抛出错误,总是Lambda由于TimeoutError而完成调用 < li >如果调用成功或不成功,< code > cache DDB . server config . is connected()返回true ` < li >导致超时的业务逻辑部分是对MongoDB本身的查询,常见的MongoDB操作如对非常小的集合(最多100个文档)的< code>findOne或< code > update one < li >我们尝试在https://github.com/Automattic/mongoose/issues/8180之后将NodeJS上的MongoDB驱动程序从< code>3.3.1升级到< code>3.3.5(不过我们没有使用mongoose,只是使用了官方的mongodb NodeJS驱动程序),但问题仍然存在 < li >我们尝试通过使用相同版本驱动程序的NodeJS脚本直接查询我们的MongoDB集群,在数千次查询中,没有出现一次超时问题。所以我们得出结论,问题不在于我们的集群本身,而在于连接。 < li >调用非常频繁的函数不会比定期调用的函数更频繁地超时,但是调用不太频繁。看起来,我们到MongoDB的缓存连接不知何故变得陈旧了,即使在调用< code>isConnected()时返回< code>true,并且在Lambda容器保持打开一段时间而没有调用之后不能被重用。我们使用默认超时:https://scale grid . io/blog/understanding-MongoDB-client-time out-options/ < li >检查了Atlas上的MongoDB日志条目-没有任何可疑之处 < li >停止检查数据库连接解决了这个问题,但会使大多数API调用变慢2-3倍,我们仍然希望了解问题的根源

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

共有1个答案

花博厚
2023-03-14

我们公司目前使用相同的架构(Lambda-

以下是我们使用的代码:

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上使用缓存的数据库和客户端:

/**
 * 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连接。此后,版本 4 中的驱动程序使用以下代码在内部弃用和处理了此问题:

// If a connection already been established, we can terminate early
  if (mongoClient.topology && mongoClient.topology.isConnected()) {
    return callback(undefined, mongoClient);
  }

可能发生的另一件事是Lambda偶尔会被破坏/损坏。对于Lambda来说,这是无法预防的正常行为,这就是为什么AWS建议在您的程序中内置重试策略。

请注意,即使是AWS SDK,其文档中也有重试策略:

AWS CLI和AWS SDK等客户端会重试客户端超时、节流错误(429)和其他不是由错误请求导致的错误。

 类似资料:
  • 我们在ignite中面临着间歇性的性能问题,响应时间变得非常高,我们在日志中看到了下面的错误。我们有10个索引列,我没有看到索引有任何问题,因为“where”子句中的所有列都被索引了。联接发生在具有亲和性共定位的字段上,这意味着联接只发生在特定节点中的数据上,而不发生在Across ;节点上。 请让我知道你是否能在这方面提供任何帮助。  > Apache Ignite版本:2.7.5 启用Igni

  • 问题内容: 我们的数据库中有一个函数,该函数搜索两个大表以查看是否存在值。这是一个相当大的查询,但已对其进行了优化以使用索引,并且通常运行速度非常快。 在过去的2周中,此功能有3次决定进入麻烦境地,并且运行极其缓慢,这会导致死锁和性能下降。即使在少于高峰使用时间的情况下,也会发生这种情况。 在SQL Server中使用“更改功能”重建功能似乎可以解决此问题。完成后,服务器使用率将恢复正常,一切正常

  • 我在两个不同的API项目上断断续续地收到以下错误。API项目已正常运行近一年,没有变化。当错误开始发生时,它会以持续几分钟的突发方式发生,然后再次开始正常运行。错误事件每小时发生几次,我们在12小时前的昨晚早些时候注意到错误发生。感谢任何帮助。 接口范围:www.googleapis.com/auth/userinfo.profile www.googleapis.com/auth/userinf

  • 问题内容: 我有一个通过Apache https proxypass在Tomcat上运行的Java Spring Web应用程序,当它尝试访问安全的IBM Watson服务时间歇性地失败。Apache通过LetsEncrypt证书进行安全保护,该证书重定向到Tomcat端口8080。 环境: Java:jdk1.7.0_80 Solaris 10 Tomcat 8.0.33 Apache2.4.1

  • 我已经编写了一个程序,从usb摄像头捕获图像,并根据检测到的每帧颜色跟踪对象的位置。间歇性(可能在1分钟、10分钟或半小时后发生)我收到错误消息: 我遵循的流程是: 用相机拍摄一帧,cap=cv2。视频捕获(1)/cap。read() 变换几何,cv2。透视图 高斯模糊滤波器,cv2。高斯模糊 BGR到HSV转换,cv2。CVT彩色(模糊帧,cv2.COLOR\u BGR2HSV) 轮廓发现和分析

  • 我在打Rest电话时遇到了tomcat的间歇性问题。设置: 应用程序在portX上运行独立的tomcat Application B在portY上的另一个独立tomcat上运行,两个tomcat安装都在同一台机器上。Java版本是JRE6 下面的参数被添加到bash profile-Dhttp中的JVM_OPTS中。代理主机=[主机]-Dhttp。proxyPort=[端口]-Dhttp。非Pro