【问题标题】:Firestore performance issues when compared to Firestore emulator与 Firestore 模拟器相比,Firestore 性能问题
【发布时间】:2020-12-10 01:20:51
【问题描述】:

在某些情况下,我的应用可能有大量的写入、读取和更新(甚至可以超过 10000 次)。

在本地开发应用程序时,这些操作通常最多需要几秒钟(太棒了!)但是,在谷歌云上运行应用程序时很容易需要几分钟,以至于 Firebase 函数超时。

我在一个单独的项目中开发了一个受控测试,其唯一目的是编写、获取和删除数千个项目以进行基准测试。这些是结果(从几次测试中得出的平均值):

Local Emulator:
5000 items,                   4.2s write,  2.2s delete
5000 items, batch mode ON,    0.75s write, 0.11s delete

Cloud Firestore:
100 items,                    15.8s write, 14.5s delete
1000 items, batch mode ON,    4.8s write,  3.0s delete
5000 items, async mode ON,    10.2s write, 8.0s delete
5000 items, batch & async ON, 4.5s write,  3.9s delete

注意:每当我尝试异步执行数据库操作时,我的本地模拟器就会崩溃(这又是一个问题),但这就是为什么我无法在本地异步测试写入/删除速度的原因。此外,写入和读取值通常在运行之间变化 +-25%。

但是,如您所见,与云中最快的测试相比,我的本地模拟器在其最慢模式下的速度更快,这一事实肯定会引发一些问题。

可能是我有某种配置问题吗?还是仅仅是这些数字是 Firestore 的标准?如果您想尝试,这里是(总结的)打字稿代码:

functions.runWith({ timeoutSeconds: 540, memory: "2GB" }).https.onRequest(async (req, res) => {
  //getting the settings from the request
  var data = req.body;
  var numWrites: number = data.numWrites;
  var syncMode: boolean = !data.asyncMode;
  var batchMode: boolean = data.batchMode;
  var batchLimit: number = data.batchLimit;

  //pre-run setup
  var dbObj = {
    number: 123,
    string: "abc",
    boolean: true,
    object: { var1: "var1", num1: 1 },
    array: [1, 2, 3, 4]
  };
  var collection = db.collection("testCollection");
  var startTime = moment();

  //insert requested number of items, using requested settings
  var allInserts: Promise<any>[] = [];
  if (!batchMode) { //sequential writes
    for (var i = 0; i < numWrites; i++) {
      var set = collection.doc().set(dbObj);
      allInserts.push(set);
      if (syncMode) await set;
    }
  } else { //batch writes
    var batch = db.batch();
    for (var i = 1; i <= numWrites; i++) {
      batch.set(collection.doc(), dbObj);
      if (i % batchLimit === 0) {
        var commit = batch.commit();
        allInserts.push(commit);
        batch = db.batch();
        if (syncMode) await commit;
      }
    }
  }

  //some logging information. Getting items to delete
  var numInserts = allInserts.length;
  await Promise.all(allInserts);
  var insertTime = moment();
  var alldocs = (await collection.get()).docs;
  var numDocs = alldocs.length;
  var getTime = moment();

  //deletes all of the items in the collection
  var allDeletes: Promise<any>[] = [];
  if (!batchMode) { //sequential deletes
    for (var doc of alldocs) {
      var del = doc.ref.delete();
      allDeletes.push(del);
      if (syncMode) await del;
    }
  } else { //batch deletes
    var batch = db.batch();
    for (var i = 1; i <= numDocs; i++) {
      var doc = alldocs[i - 1];
      batch.delete(doc.ref);
      if (i % batchLimit === 0) {
        var commit = batch.commit();
        allDeletes.push(commit);
        batch = db.batch();
        if (syncMode) await commit;
      }
    }
  }

  var numDeletes = allDeletes.length;
  await Promise.all(allDeletes);
  var deleteTime = moment();

  res.status(200).send(/* a whole bunch of metrics for analysis */);
});

编辑:澄清一下,UI 不执行这些写入操作,因此最终用户机器和云服务器之间的延迟(理论上)应该不会导致任何重大延迟问题。与数据库的通信完全由Firebase Functions

处理

编辑 2:我在两个部署中运行了这个测试,一个在欧洲,另一个在美国。两者的运行时间差不多,尽管我对这两个服务器的 ping 有很大不同

【问题讨论】:

    标签: node.js typescript firebase google-cloud-firestore google-cloud-functions


    【解决方案1】:

    本地模拟器的响应速度比 Cloud Firestore 更快是正常的,因为远程环境会增加需要时间的网络流量。

    对于来自单一来源的大量操作,建议使用batch operations,因为这将减少事务,并随之减少往返次数。

    异步模式更快的原因是调用者在发送下一个事务之前没有等待每个事务完成所以调用更快也是有道理的。

    在我看来,你摆在桌面上的时间很正常。

    作为要优化的附加事项,请确保您的 Firestore 数据库所在的区域离您的位置最近。

    【讨论】:

    • 我会支持何塞所说的,这可能是网络延迟。您可以查看 gcping.com 以查看从您的机器到您正在使用的云区域的网络延迟是多少。将其乘以您正在进行的往返次数,以了解网络导致的额外延迟。
    • 我的代码不是写到 firestore 的 UI,而是与 firestore 对话的云函数。当然 google-cloud-functions 和 firestore 之间的延迟可以忽略不计,不会影响性能
    猜你喜欢
    • 2020-10-19
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 2021-08-25
    • 1970-01-01
    • 2021-06-30
    相关资源
    最近更新 更多