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

2023-11-23

火力战士在这里

当我最近tweeted关于新的increment()Firebase实时数据库中的操作员,有队友问有多快increment() is.

我一直想知道同样的问题:你能以多快的速度增加一个值increment(1)?与此相比如何使用事务来增加值?


TL;DR

我测试了这些情况:

  1. 用 a 增加一个值transaction call:

    ref.transaction(function(value) {
      return (value || 0) + 1;
    });
    
  2. 用新的增加一个值increment操作员:

    ref.set(admin.database.ServerValue.increment(1));
    

增量更快这一事实并不令人意外,但是……增量是多少?

Results:

  • 通过事务,我每秒可以增加大约 60-70 次的值。
  • 随着increment操作员,我每秒能够增加大约 200-300 次的值。

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

我在我的 2016 型号 MacBook pro 上运行了测试,并将上述内容包装在一个简单的 Node.js 脚本中,该脚本使用客户端节点SDK。操作的包装脚本也非常基本:

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

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

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

测试注意事项:

  1. 我不断增加进程数量,直到“每秒增量”似乎达到最大值,但我注意到这与我的笔记本电脑风扇全速运转同时发生。所以很可能我没有找到服务器端操作的真正最大吞吐量,而是我的测试环境和服务器的结合。因此,当您尝试重现此测试时,很有可能(事实上很可能)您可能会得到不同的结果,尽管当然increment吞吐量应始终显着高于transaction。无论您得到什么结果:请分享它们。 :)

  2. 我使用了客户端 Node.js SDK,因为它最容易工作。使用不同的 SDK 可能会产生稍微不同的结果,尽管我预计主要的 SDK(iOS、Android 和 Web)与我得到的结果非常接近。

  3. 两个不同的队友立即问我是否会在单个节点上运行它,或者是否并行增加多个值。并行增加多个值可能会显示是否存在系统范围的吞吐量瓶颈或者是否是特定于节点的(我期望如此)。

  4. 正如已经说过的:我的测试工具没什么特别的,但我的 jsbin 观察者代码特别可疑。如果有人想在相同的数据上编写一个更好的观察者,那么值得赞扬。


交易和增量运算符如何在幕后工作

了解之间的性能差异transaction and increment了解这些操作的幕后工作原理确实很有帮助。对于 Firebase 实时数据库,“幕后”是指通过 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

TODO:更新上面的图表,以便服务器上的操作不会重叠。

第二个客户端必须再次重试其操作,因为服务器端值在第一次和第二次尝试之间已被修改。我们向此位置写入的客户端越多,您看到重试的可能性就越大。 Firebase 客户端会自动执行这些重试,但在多次重试后,它将放弃并引发Error: maxretry申请的例外。

这就是我每秒只能增加计数器约 60-70 次的原因:如果写入次数超过此数量,则节点上的争用过多。

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

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

            Client            Server                Client

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

仅最后两个流程图的长度就足以解释原因increment在这种情况下要快得多:increment操作就是为此而进行的,因此有线协议更能代表我们想要实现的目标。仅在我的简单测试中,这种简单性就会导致 3 到 4 倍的性能差异,在生产场景中甚至可能更大。

当然,事务仍然有用,因为除了递增/递减之外,还有更多的原子操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

您可以以多快的速度自动增加 Firebase 实时数据库上的值? 的相关文章

  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 使用模数按字母顺序对列表进行排序

    我在获取元素列表并按字母顺序对它们进行排序方面没有任何问题 但我很难理解如何使用模数来做到这一点 更新 这是按我的方式工作的代码 但是 我更喜欢下面提供的答案的可重用性 因此接受了该答案
  • Meteor:应用程序无法在 0.9.1.1 版本上运行

    出现类似错误 Error TypeError undefined is not a function evaluating Template create anonymous function iron dynamic template j
  • 使用 Angular 下载具有动态 src 的脚本

    Angular 提供了通过动态名称动态加载模板的方法ng include 该部分中的内联 JS 和 CSS 可以正常加载 但没有一个好的方法来下载带有动态 url 的脚本 我们需要下载脚本 相对于调用它们的 html 部分的路径 即我们有一
  • Node.js:如何在检索数据(块)时关闭响应/请求

    我正在用 node js 构建一个应用程序 它加载多个页面并分析内容 因为 node js 发送块 所以我可以分析这些块 如果一个块包含例如索引 nofollow 我想关闭该连接并继续其余部分 var host example com to
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • 标签获取 href 值

    我有以下 html div class threeimages a img alt Australia src Images Services 20button tcm7 9688 gif a div class text h2 a hre
  • 在requestAnimationFrame中使用clearRect不显示动画

    我正在尝试在 HTML5 画布上做一个简单的 javascript 动画 现在我的画布是分层的 这样当我收到鼠标事件时 背景层不会改变 但带有头像的顶层会移动 如果我使用 requestAnimationFrame 并且不清除屏幕 我会看到
  • 跟踪用户何时点击浏览器上的后退按钮

    是否可以检测用户何时单击浏览器的后退按钮 我有一个 Ajax 应用程序 如果我可以检测到用户何时单击后退按钮 我可以显示适当的数据 任何使用 PHP JavaScript 的解决方案都是优选的 任何语言的解决方案都可以 只需要我可以翻译成
  • Babel 7 Jest Core JS“TypeError:wks不是函数”

    将我的项目升级到 Babel 7 后 通过 Jest 运行测试会抛出以下错误 测试在 Babel 6 中运行没有任何问题 但在 Babel 7 中失败并出现以下错误 TypeError wks is not a function at Ob
  • 如何获取 vuejs 组件单元测试中定义的“this”变量

    我正在尝试在 npm 脚本中使用 mocha webpack 来测试 vuejs 组件 我在测试中像这样嘲笑 vuex 商店 const vm new Vue template div div
  • 提交表单并重定向页面

    我在 SO 上看到了很多与此相关的其他问题 但没有一个对我有用 我正在尝试提交POST表单 然后将用户重定向到另一个页面 但我无法同时实现这两种情况 我可以获取重定向或帖子 但不能同时获取两者 这是我现在所拥有的
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • 为 illustrator 导出脚本以保存为 web jpg

    任何人都可以帮我为 illustrator CC2017 编写一个脚本 将文件以 JPG 格式导出到网络 旧版 然后保存文件并关闭 我有 700 个文件 每个文件有 2 个画板 单击 文件 gt 导出 gt 另存为 Web 旧版 然后右键文
  • 为什么在 Internet Explorer 中访问 localStorage 对象会引发错误?

    我正在解决一个客户端问题 Modernizr 意外地没有检测到对localStorageInternet Explorer 9 中的对象 我的页面正确使用 HTML 5 文档类型 并且开发人员工具报告该页面具有 IE9 的浏览器模式和 IE
  • 模块构建失败(来自 ./node_modules/babel-loader/lib/index.js)Vue Js

    我从 GitHub 下载了一个我和我的朋友正在开发的项目 但是当我尝试运行时 npm run serve 我收到这个错误 src main js 中的错误 Module build failed from node modules babe
  • 为什么我不能在 AngularJS 中使用 data-* 作为指令的属性名称?

    On the t他的笨蛋 http plnkr co edit l3KoY3 p preview您可以注意到属性名称模式的奇怪行为data 在指令中 电话 Test of data named attribute br
  • 如何更改此 jquery 插件的时区/时间戳?

    我正在使用这个名为 timeago 的插件 在这里找到 timeago yarp com 它工作得很好 只是它在似乎不同的时区运行 我住在美国东部 费城时区 当我将准确的 EST 时间放入 timeago 插件时 比如 2011 05 28
  • JQuery 图像上传不适用于未来的活动

    我希望我的用户可以通过帖子上传图像 因此 每个回复表单都有一个上传表单 用户可以通过单击上传按钮上传图像 然后单击提交来提交帖子 现在我的上传表单可以上传第一个回复的图像 但第二个回复的上传不起作用 我的提交过程 Ajax 在 php 提交
  • 如何仅在最后一个
  • 处给出透明六边形角度?
  • 我必须制作这样的菜单 替代文本 http shup com Shup 330421 1104422739 My Desktop png http shup com Shup 330421 1104422739 My Desktop png

随机推荐

  • 如何在网页上制作pandas操作的进度条

    我已经在谷歌上搜索了一段时间 但无法找到一种方法来做到这一点 我有一个简单的 Flask 应用程序 它接受 CSV 文件 将其读入 Pandas 数据帧 将其转换并输出为新的 CSV 文件 我已经成功上传并使用 HTML 转换它 div c
  • 另一个围栏代码块内的围栏代码块

    我正在尝试写有关 Markdown 语法的文章 并且为了编写它 我使用 Markdown 所以 我的文档如下所示 Example of markdown code foo fenced code block fail bar lalala
  • AppFabric 缓存 - 我可以指定用于所有对象的序列化样式吗?

    实现某些自定义序列化的对象可以序列化和反序列化为不同的格式 例如 Xml 或 byte 我遇到了一个问题 当我放入缓存时 AppFabric 在类上运行 IXmlSerialized 实现 而我宁愿强制它使用二进制文件 AppFabric
  • 如何使用 adb 卸载所有 3rd 方用户应用程序?

    我正在尝试创建一个脚本 该脚本将通过以下方式在一次批量操作中检索和卸载所有用户应用程序adb 有谁知道我怎样才能做到这一点 我目前可以通过以下方式列出所有 3rd 方应用程序 adb shell pm list packages 3 我可以
  • 我如何知道图片何时加载到 Picturebox 中

    我有一些巨大的图像 7000 5000 要在我的程序中同时加载 我将它们一张一张地显示在图片框中 这些图像需要一些时间才能加载到图片框 首先 我将所有图像加载到Image数组为Bitmap 然后我只显示图片框中的第一张图像picturebo
  • Numpy:条件和

    我有以下 numpy 数组 import numpy as np arr np array 1 2 3 4 2000 5 6 7 8 2000 9 0 1 2 2001 3 4 5 6 2001 7 8 9 0 2002 1 2 3 4 2
  • 平方根函数是如何实现的? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 平方根函数是如何实现的 简单的实现使用二分查找用C double root double n Max and min are used to take into account
  • 如何在 selenium 自动化中更改 chrome 浏览器语言

    我想自动化 Web 应用程序的本地化功能 根据我的应用程序 当浏览器语言更改时 应用程序语言应该根据浏览器语言自动更改 怎么做 在启动驱动程序之前 在 chrome 选项中设置语言代码 如下所示 System setProperty web
  • Eclipse 无法编译,类文件错误,版本错误

    我正在尝试编译从另一个开发人员处签出的 SVN 代码 Eclipse 最近给我带来了很多麻烦 Here are my project specific settings 这是我的 ant 文件的编译部分
  • 哪个编译器(如果有)在参数包扩展中存在错误?

    在尝试以容器形式访问元组的便捷方法时 我编写了一个测试程序 在 clang 3 9 1 和 apple clang 上 它按预期进行编译 产生预期的输出 1 1 foo 2 在 gcc 5 4 6 3 上 无法编译
  • 如何在 Chrome 扩展程序中使用 Google API?

    我现在正在花几个小时搜索如何在 Chrome 扩展中使用 Google API 我想做的就是解析网站的内容并将其作为新事件插入到 Google 日历中 我得到了解析和一切 但似乎不可能在 Chrome 扩展中使用 Google API 我只
  • 如何改变objective-c中的图像分辨率

    我需要更改 Objective C 中现有图像的分辨率 就像 Apple 的预览应用程序工具 gt 调整大小 gt 分辨率一样 请让我知道可能的解决方案 这是我用过的一个很棒的示例 http weblog scifihifi com 200
  • Internet Explorer 8 中的 jQuery 问题

    我正在尝试让我的 jQuery 函数在 IE8 上运行 我正在从 Google 的服务器加载该库 http ajax googleapis com ajax libs jquery 1 3 jquery min js The functio
  • 我应该以什么顺序发送信号来正常关闭进程?

    In a comment on 这个答案另一个的question 评论者说 除非绝对不要使用kill 9 必要的 SIGKILL 不能被捕获 所以 被杀死的程序无法运行任何程序 关闭例程 例如擦除 临时文件 首先尝试 HUP 1 然后 IN
  • IHostedService 无故停止

    谁能向我解释为什么我的服务器无缘无故停止了 下面是我的 IHostedService 实现 public class HostServiceBox IHostedService public Task StartAsync Cancella
  • 如何从 JAR 中提取文件夹

    我需要复制一个文件夹 在运行时打包在 Jar 中 我想通过调用也包含在同一文件夹中的类中的函数来做到这一点 我尝试过使用getSystemResource URL sourceDirUrl ClassLoader getSystemReso
  • 如何使用 C 的 mmap() 更改文本文件中的字符?

    假设我将标准的 Hello World n 保存到名为 hello txt 的文本文件中 如果我想将 H 更改为 R 或其他内容 我可以使用 mmap 来实现吗 mmap标准 C99 或 C11 规范中不存在 它是在 POSIX 中定义的
  • 正则表达式 - 匹配不带空格的字符串

    构建一个正则表达式 该表达式将拒绝包含空格的输入字符串 我有以下表达式 但它不起作用 a zA Z0 9 S 有效案例 String123 test string without space 无效案例 String123 test cont
  • 我们如何存储到 NSDictionary 中? NSDictionary 和 NSMutableDictionary 有什么区别?

    我正在开发一个应用程序 我想在其中使用NSDictionary 任何人都可以给我发送一个示例代码来解释如何使用NSDictionary用一个完美的例子来存储数据 The NS词典 and NSMutableDictionary文档可能是您最
  • 您可以以多快的速度自动增加 Firebase 实时数据库上的值?

    火力战士在这里 当我最近tweeted关于新的increment Firebase实时数据库中的操作员 有队友问有多快increment is 我一直想知道同样的问题 你能以多快的速度增加一个值increment 1 与此相比如何使用事务来