NestJS Mongoose 连接在负载测试时终止

Asa*_*fir 6 mongoose mongodb nestjs

当多个开发人员使用我的 API 时,多个并发请求将被发送到 Mongoose。当并发量很高时,连接就会“死亡”并拒绝满足任何新请求,无论我等待多长时间(几个小时!)。

我只是想说,正常使用时一切正常。大量使用会导致连接崩溃。

我的 MongooseModule 初始化:

MongooseModule.forRoot(DatabasesService.MONGO_FULL_URL, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
  autoEncryption: {
    keyVaultNamespace: DatabasesService.keyVaultNamespace,
    kmsProviders: DatabasesService.kmsProviders,
    extraOptions: {
      mongocryptdSpawnArgs: ['--pidfilepath', '/tmp/mongocryptd.pid']
    }
  } as any
})
Run Code Online (Sandbox Code Playgroud)

导入功能的模块:

@Module({
  imports: [MongooseModule.forFeature([{ name: 'modelName', schema: ModelNameSchema }])],
  providers: [ModelNameService],
  controllers: [...],
  exports: [...]
})
Run Code Online (Sandbox Code Playgroud)

服务:

@Injectable()
export class ModelNameService {
  constructor(
    @InjectModel('modelName') private modelName: Model<IModelName>
  ) {}

  async findAll(): Promise<IModelName[]> {
    const result: IModelName[] = await this.modelName.find().exec();
    if (!result) throw new BadRequestException(`No result was found.`);
    return result;
  }
}
Run Code Online (Sandbox Code Playgroud)

我尝试过使用不同的实用程序进行负载测试,最简单的是:

ab -c 200 -n 300 -H "Authorization: Bearer $TOKEN" -m GET -b 0 https://example.com/getModelName
Run Code Online (Sandbox Code Playgroud)

连接挂起后的任何新请求都会卡在 ModelNameService.findAll() 第一行(对 mongo 的请求)。

在详细程度为“-vvvvv”的 mongodb 日志上,我可以看到一些可疑的行:

User Assertion: Unauthorized: command endSessions requires authentication src/mongo/db/commands.cpp

Cancelling outstanding I/O operations on connection to 127.0.0.1:33134
Run Code Online (Sandbox Code Playgroud)

而且我还发现它不会同时打开超过 12 个连接。它总是等待关闭一个,然后再打开一个新的。

其他要点:

  • Mongoose 不返回任何值或通知任何错误。它只是挂起而不通知任何东西。
  • 终端健康检查能够 ping 数据库并返回健康状态。
  • NestJS API 仍然有效 - 我能够发送新请求并接收响应。仅与错误连接相关的请求挂起。
  • 当我注入连接并检查它时,readyState它会返回connected
  • 重新启动 API 即可立即修复该问题。
  • MongoDB 本身保持正常工作。
  • 增加 MongoosepoolSize能够同时处理更多请求,但在请求量更大时仍然会崩溃。

我的主要问题是我该如何处理这个案子?目前,我添加了另一个运行状况检查,尝试每半分钟向有问题的连接发送一次查询,如果 k8s 确定出现故障,则会重新启动 pod。这可行,但不是最佳的。