【问题标题】:Firebase Admin SDK slow on cold starts in Firebase FunctionFirebase Admin SDK 在 Firebase 函数中的冷启动速度很慢
【发布时间】:2022-01-20 03:21:55
【问题描述】:

我在 Firebase Functions 中使用 Firebase Admin SDK 来列出 Cloud Storage 上目录的内容。但是,我的功能通常需要超过 5 秒以上的时间来回答。起初我认为这都是由于函数本身的冷启动,我尝试了很多方法来防止函数的冷启动,例如:

  • minInstances 设置为 1 或更多
  • 使用 cronjob 每分钟调用一次函数(无需身份验证,因此它实际上不使用 admin sdk 但仍保持函数温暖)
  • 将函数拆分为单独的文件以减少冷启动时间 (https://stackoverflow.com/a/47985480/13370504)
  • 尝试将功能移近云存储(us-central1europe-west3

但是,上述方法均无效,并且在第一次调用该函数时,我的响应时间仍然很慢。在函数中添加一些日志记录后,事实证明,Admin SDK 需要一秒钟多的时间才能从实时数据库中获取单个值,并且在 Cloud Storage 上运行 getFiles 命令通常需要 5 秒钟以上(目录通常只包含一个文件)。

例如,对于下面的代码,我得到以下控制台输出:

listVideos: coldstart true
listVideos: duration 1: 0ms
listVideos: duration 2: 1302ms (realtime database)
listVideos: duration 3: 6505ms (getFiles on cloud storage)
listVideos: coldstart false
listVideos: duration 1: 0ms
listVideos: duration 2: 96ms (realtime database)
listVideos: duration 3: 199ms (getFiles on cloud storage)

我的函数如下所示:

import * as admin from "firebase-admin";

admin.initializeApp();

let coldStart = true;
exports.listVideos = functions.region("europe-west1").runWith({
  memory: "128MB",
  minInstances: 1,
}).https.onCall(async (data, context) => {
  console.log("coldstart", coldStart);
  coldStart = false;
  const t1 = new Date().getTime();
  if (context.auth) {
    const authUid = context.auth.uid;

    console.log(`duration 1: ${new Date().getTime() - t1}ms`);
    const level = (await admin.database().ref(`users/${authUid}/`).once("value")).val();
    console.log(`duration 2: ${new Date().getTime() - t1}ms (realtime database)`);

    const [files] = await admin.storage().bucket()
        .getFiles({
          prefix: `${authUid}/video`,
        });
    console.log(`duration 3: ${new Date().getTime() - t1}ms (getFiles on cloud storage)`);
    return {status: "success", files: files};
  } else {
    return {status: "error - not authenticated"};
  }
});

我知道我不能期待 0 毫秒的延迟,但是对于一个简单的 getFiles 调用,我希望在 1 秒内完成一些事情,就像 sdk “温暖”时一样(考虑到我的整个存储桶的文件少于 1000 个)并且我列出的目录中只有 1 个文件)

【问题讨论】:

  • 您没有描述GCS存储桶中的数据。所以 GCS 文件大小会影响时间。另外,请记住这是一个下载,而不是一个列表,所以它都与对象的大小有关。然后,您抱怨的另一个延迟是调用 RTDB 查找的 1 秒时间。这又取决于地区。如果可能的话,我希望您在与 RTDB 相同区域的 VM 上在 CF 之外测试这些(请记住,对于 RTDB,这是由 firebase 项目创建设置的,无法更改)并测量响应时间?
  • 如果结果相同,则更多地与您部署的位置和您正在拨打的电话类型有关。然后以同样的方式对 Firestore get() 重复测试。您应该记录对象的开始和结束时间,加上大小并添加 bps 计算以显示吞吐量。如果您只列出对象,一个侧面测试是看看它是否仍然很慢。
  • @PriyashreeBhadra 我的文件大小在 10-400mb 之间。根据我从文档ref 得到的信息,这些文件没有被下载(只有元数据),所以文件大小无关紧要。我在本地使用 firebase 函数模拟器运行应用程序并获得以下冷启动时间:@​​987654332@。有趣的是,我在 GitHub 上发现了这个问题,我认为这是我的问题的根本原因:github.com/googleapis/nodejs-storage/issues/951
  • @PriyashreeBhadra 澄清一下:我使用 firebase 模拟器在本地运行这些功能,但连接到比利时数据中心 (europe-west1) 中的实时数据库和云存储。

标签: firebase firebase-realtime-database google-cloud-functions google-cloud-storage firebase-admin


【解决方案1】:

Cloud Storage 不是数据库,也没有针对查询进行优化(getFiles 实际上是使用对象名称的前缀对整个存储桶进行查询)。当您已经知道对象的名称时,它已针对大规模存储和检索数据块进行了优化。

如果您想快速列出文件,请考虑将文件的元数据存储在针对您要执行的查询类型优化的数据库中,并将这些记录链接到您的存储中需要。这是 GCP 项目中相当普遍的做法。

【讨论】:

  • 谢谢道格!您是否解释了为什么第一个 getFiles 查询总是在 5+ 秒左右,而后续调用却在 200 毫秒以下? Cloud Storage 在第一次调用后会执行一些缓存,还是只是 Admin SDK 需要花费大量时间来初始化?对于一个简单的查询(超过一秒),即使是实时数据库也需要更多的冷启动时间。
  • 您可以预期在 SDK 初始化(可能是惰性的)和建立到服务的套接字时会有一些开销。如果您想了解 GCP SDK 的功能、自行构建它们,甚至添加您自己的内部基准,GCP SDK 都是开源的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
  • 2018-03-20
相关资源
最近更新 更多