gpt4 book ai didi

javascript - 您能以多快的速度自动增加Firebase实时数据库上的值?

转载 作者:行者123 更新时间:2023-12-01 14:56:19 25 4
gpt4 key购买 nike

在这里放火

当我最近在Firebase实时数据库中使用新的increment()运算符tweeted时,一个队友问increment()有多快。

我一直在想同样的事情:您可以使用increment(1)多快增加一个值?与using a transaction to increment a value相比又如何呢?

最佳答案

TL; DR

我测试了这些情况:

  • 通过transaction调用增加一个值:
    ref.transaction(function(value) {
    return (value || 0) + 1;
    });
  • 使用新的increment运算符递增一个值:
    ref.set(admin.database.ServerValue.increment(1));

  • 增量更快的事实不足为奇,但是...要增加多少呢?

    结果:
  • 通过事务,我每秒可以增加大约60-70次的值。
  • 使用increment运算符,我每秒可以增加大约200-300次的值。


  • 我如何进行测试并获得这些数字

    我已经在我的2016年型号macBook pro上进行了测试,并将以上内容包装在使用 client-side Node SDK的简单Node.js脚本中。这些操作的包装脚本实际上也很基本:
    timer = setInterval(function() {
    ... the increment or transaction from above ...
    }, 100);

    setTimeout(function() {
    clearInterval(timer);
    process.exit(1);
    }, 60000)

    因此:每秒增加10次该值,然后在1分钟后停止这样做。然后,我使用以下脚本生成此过程的实例:
    for instance in {1..10}
    do
    node increment.js &
    done

    因此,这将使用 increment运算符运行10个并行进程,每个进程每秒将值增加10次,总计每秒增加100次。然后,我更改了实例数,直到“每秒增量”达到峰值。

    然后,我写了一个小 script on jsbin来监听该值,并通过一个简单的低通,移动平均滤波器确定每秒的增量数。我在这里遇到了麻烦,因此不确定计算是否完全正确。鉴于我的测试结果,他们已经足够接近了,但是如果有人想写一个更好的观察者:请成为我的客人。 :)

    有关测试的注意事项:
  • 我一直在增加进程数,直到“每秒增量”似乎已达到最大值,但我注意到这与我的笔记本电脑爱好者全速运行的时间吻合。因此,我可能没有找到服务器端操作的真正最大吞吐量,而是找到了我的测试环境和服务器的结合。因此,当您尝试重现此测试时,很可能(实际上很可能)会得到不同的结果,尽管increment吞吐量当然应该总是比transaction高得多。不管您得到什么结果:请分享。 :)
  • 我已经使用了客户端Node.js SDK,因为它最容易上手。使用不同的SDK可能会产生稍微不同的结果,尽管我希望主要的SDK(iOS,Android和Web)与我所获得的非常接近。
  • 两个不同的队友立即问我是否要在单个节点上运行它,或者是否要同时并行增加多个值。并行增加多个值可能会显示是否存在系统范围的吞吐量瓶颈,或者它是否是特定于节点的(我期望)。
  • 如前所述:我的测试工具没什么特别的,但是我的jsbin观察者代码尤其令人怀疑。如果有人想在相同的数据上编写更好的观察者,则表示荣誉。


  • 交易和增量运算符(operator)如何在后台工作

    要了解 transactionincrement之间的性能差异,确实有助于了解这些操作的工作原理。对于Firebase Realtime Database,“在幕后”意味着通过Web Socket连接在客户端和服务器之间发送的命令和响应。

    Firebase中的事务使用比较并设置方法。每当我们像上面那样开始事务时,客户端都会猜测节点的当前值。如果从未看到该节点,则猜测为 null。它用这个猜测调用事务处理程序,然后我们的代码返回新值。客户端将猜测和新值发送到服务器,服务器执行比较并设置操作:如果猜测正确,请设置新值。如果猜测是错误的,则服务器将拒绝该操作,并将实际的当前值返回给客户端。

    在理想情况下,最初的猜测是正确的,并且该值会立即写入服务器上的磁盘(此后,发送给所有监听器)。在流程图中,如下所示:
                Client            Server

    + +
    transaction() | |
    | |
    null | |
    +---<-----+ |
    | | |
    +--->-----+ |
    1 | (null, 1) |
    +--------->---------+
    | |
    +---------<---------+
    | (ack, 3) |
    | |
    v v

    但是,如果节点在服务器上已经有一个值,它将拒绝该写操作,发送回实际值,然后客户端再次尝试:
                Client            Server

    + +
    transaction() | |
    | |
    null | |
    +---<-----+ |
    | | |
    +--->-----+ |
    1 | |
    | (null, 1) |
    +--------->---------+
    | |
    +---------<---------+
    | (nack, 2) |
    | |
    2 | |
    +---<-----+ |
    | | |
    +--->-----+ |
    3 | (2, 3) |
    +--------->---------+
    | |
    +---------<---------+
    | (ack, 3) |
    | |
    | |
    v v

    这还算不错,一个额外的往返。即使Firebase会使用悲观锁定,也需要该往返,所以我们不会丢失任何东西。

    如果多个客户端正在同时修改相同的值,则问题开始。这在节点上引入了所谓的争用,如下所示:
                Client            Server                Client
    + + +
    transaction() | | |
    | | | transaction()
    null | | |
    +---<-----+ | | null
    | | | +--->----+
    +--->-----+ | | |
    1 | | +---<----+
    | (null, 1) | | 1
    +--------->---------+ (null, 1) |
    | |---------<---------+
    +---------<---------+ |
    | (nack, 2) |--------->---------+
    | | (nack, 2) |
    2 | | |
    +---<-----+ | | 2
    | | | |--->----+
    +--->-----+ | | |
    3 | (2, 3) | |---<----+
    +--------->---------+ | 3
    | | |
    +---------<---------+ |
    | (ack, 3) | (2, 3) |
    | |---------<---------+
    | | |
    | |--------->---------+
    | | (nack, 3) |
    | | | 3
    | | |--->----+
    | | | |
    | | |---<----+
    | | | 4
    | | (3, 4) |
    | |---------<---------+
    | | |
    | |--------->---------+
    | | (ack, 4) |
    | | |
    v v v

    待办事项:更新上面的图表,以使服务器上的操作不会重叠。

    第二个客户端必须对其操作进行另一次重试,因为服务器端的值已在其第一次尝试和第二次尝试之间进行了修改。我们写给该位置的客户越多,您看到重试的可能性就越大。 Firebase客户端会自动执行这些重试,但是经过多次重试后,它将放弃并向应用程序引发 Error: maxretry异常。

    这就是为什么我每秒只能增加一个计数器约60-70次的原因:写操作多于此,节点上的争用就太多了。

    增量操作本质上是原子的。您正在告诉数据库:无论当前值是什么,都将其 x设置得更高。这意味着客户端永远不必知道节点的当前值,因此也不会猜错。它只是告诉服务器该怎么做。

    当使用 increment时,我们具有多个客户端的流程图如下所示:
                Client            Server                Client

    + + +
    increment(1) | | |
    | | | increment(1)
    | (increment, 1) | |
    +--------->---------+ (increment, 1) |
    | |---------<---------+
    +---------<---------+ |
    | (ack, 2) |--------->---------+
    | | (ack, 3) |
    | | |
    v v v

    仅这最后两个流程图的长度就足以说明为什么 increment在这种情况下如此之快的原因:为此进行了 increment操作,因此有线协议(protocol)更紧密地表示了我们要完成的工作。这种简单性仅在我的简单测试中就导致3到4倍的性能差异,在生产场景中甚至可能更大。

    当然,事务仍然有用,因为原子操作远不止是增加/减少。

    关于javascript - 您能以多快的速度自动增加Firebase实时数据库上的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61536203/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com