Meteor在许多客户之间共享大量收藏时的效率如何?

时间:2012-10-28 21:38:41

标签: benchmarking meteor

想象一下以下情况:

  • 1,000个客户端连接到显示“Somestuff”集合内容的Meteor页面。

  • “Somestuff”是一个包含1,000件物品的系列。

  • 有人在“Somestuff”集合中插入新项目

会发生什么:

  • 客户端上的所有Meteor.Collection都将更新,即插入转发给所有客户端(这意味着向1,000个客户端发送一条插入消息)

服务器确定哪个客户端需要更新的CPU成本是多少?

是否准确只将插入的值转发给客户端,而不是整个列表?

这在现实生活中如何运作?有没有这种规模的基准或实验?

4 个答案:

答案 0 :(得分:119)

简短的回答是,只有新数据才能通过网络发送。这里' S 它是如何工作的。

Meteor服务器有三个重要部分需要管理 订阅:发布功能,它定义了什么的逻辑 订阅提供的数据;观看电子邮件的 Mongo驱动程序 数据库的变化;和合并框,它结合了所有的 客户端的有效订阅并通过网络将它们发送到 客户端。

发布功能

每次Meteor客户端订阅集合时,服务器都会运行一个 发布功能。发布功能的工作是弄清楚这个集合 其客户应具有的文档并发送每个文档属性 进入合并框。它为每个新的订阅客户端运行一次。您 可以在发布函数中放置您想要的任何JavaScript,例如 使用this.userId进行任意复杂的访问控制。发布 函数通过调用this.addedthis.changed和来将数据发送到合并框 this.removed。见 full publish documentation 更多细节。

大多数发布功能都不必使用低级别的功能 不过,addedchangedremoved API。如果发布函数返回Mongo 游标,Meteor服务器自动连接Mongo的输出 驱动程序(insertupdateremoved回调)到输入 合并框(this.addedthis.changedthis.removed)。它非常整洁 您可以在发布功能中预先进行所有权限检查 然后直接将数据库驱动程序连接到合并框而无需任何用户 代码的方式。当自动发布打开时,即使这一点也是如此 隐藏:服务器自动为每个文档中的所有文档设置查询 收集并将它们推入合并框。

另一方面,您不仅限于发布数据库查询。 例如,您可以编写一个读取GPS位置的发布函数 来自Meteor.setInterval内的设备,或轮询旧版REST API 来自其他网络服务。在这些情况下,您将发出更改 通过调用低级addedchangedremoved DDP API来合并框。

Mongo驱动程序

Mongo驱动程序的作业是观察Mongo数据库的更改 实时查询。这些查询连续运行并返回更新 通过调用addedremovedchanged回调来更改结果。

Mongo不是实时数据库。所以司机民意调查。它保持着 每个活动实时查询的最后查询结果的内存中副本。上 每个轮询周期,它将新结果与之前保存的结果进行比较 结果,计算addedremovedchanged的最小集合 描述差异的事件。如果多个呼叫者注册 对于同一个实时查询的回调,驱动程序只能查看一个副本 查询,使用相同的结果调用每个已注册的回调。

每次服务器更新集合时,驱动程序都会重新计算每个集合 该集合的实时查询(未来版本的Meteor将公开一个 扩展API,用于限制更新时重新计算的实时查询 驱动程序还会在10秒计时器上轮询每个实时查询以进行捕获 绕过Meteor服务器的带外数据库更新。

合并框

合并框的工作是结合结果(addedchangedremoved 将所有客户的活动发布功能调用到单个数据中 流。每个连接的客户端都有一个合并框。它拥有一个 客户端的最小缓存的完整副本。

在只有一个订阅的示例中,合并框为 基本上是一个传递。但更复杂的应用程序可以有多个 订阅可能会重叠。如果两个订阅都设置了 同一文档中的相同属性,合并框决定了哪个值 优先,只发送给客户端。我们还没有曝光 用于设置订阅优先级的API。目前,优先事项是 由客户订阅数据集的顺序确定。首先 订阅客户端具有最高优先级,第二个 订阅次数最高,依此类推。

因为合并框保存客户端的状态,所以它可以发送最小值 无论发布什么,每个客户端都保持最新的数据量 功能提供它。

更新时会发生什么

所以现在我们为你的场景设定了舞台。

我们有1,000个连接的客户端。每个人都订阅相同的直播 Mongo查询(Somestuff.find({}))。由于每个客户端的查询相同,因此驱动程序是 只运行一个实时查询。有1,000个活动合并框。和 每个客户的发布功能都注册了addedchanged和 该实时查询的removed将提供给其中一个合并框。 没有其他任何东西连接到合并框。

首先是Mongo司机。当其中一个客户端插入新文档时 进入Somestuff,它会触发重新计算。 Mongo司机重新开始 查询Somestuff中的所有文档,将结果与结果进行比较 以前在内存中的结果,发现有一个新文件,和 调用1,000个已注册的insert回调中的每一个。

接下来,发布功能。这里发生的事情很少:每一个 1,000个insert回调中的数据将数据推送到合并框中 致电added

最后,每个合并框都会根据它检查这些新属性 其客户端缓存的内存中副本。在每种情况下,它都会发现 价值还没有在客户端上,也没有影响现有价值。所以 合并框在与其的SockJS连接上发出DDP DATA消息 客户端并更新其服务器端内存中的副本。

总CPU成本是差异一个Mongo查询的成本加上成本 1,000个合并箱检查他们的客户'国家和建设新的 DDP消息有效负载。流过电线的唯一数据是单个数据 发送到1000个客户端中的每个客户端的JSON对象,对应于新客户端 数据库中的文档,以及来自服务器的一条RPC消息 制作原始插页的客户。

优化

这是我们一定有的计划。

  • 更高效的Mongo驱动程序。我们 optimized the driver 在0.5.1中,每个不同的查询只运行一个观察者。

  • 并非每个数据库更改都应触发重新计算查询。我们 可以进行一些自动化改进,但最好的方法是API 这让开发人员可以指定需要重新运行的查询。对于 例如,对于开发人员而言,插入消息是显而易见的 一个聊天室不应该使a中的消息的实时查询无效 第二个房间。

  • Mongo驱动程序,发布功能和合并框不需要运行 在同一个过程中,甚至在同一台机器上。一些应用 运行复杂的实时查询,需要更多的CPU来观察数据库。 其他人只有几个不同的查询(想象一下博客引擎),但是 可能有很多连接的客户端 - 这些需要更多的CPU用于合并 框。分离这些组件将让我们扩展每个组件 独立地

  • 许多数据库支持在更新行时触发的触发器 提供新旧行。使用该功能,数据库驱动程序 可以注册触发器而不是轮询更改。

答案 1 :(得分:29)

根据我的经验,在Moteor中共享大量集合时使用许多客户端在版本0.7.0.1中基本上是行不通的。我会试着解释原因。

如上文所述以及https://github.com/meteor/meteor/issues/1821中所述,流星服务器必须在合并框中保留每个客户的已发布数据的副本。这是允许Meteor魔法发生的原因,但也导致任何大型共享数据库被重复保存在节点进程的内存中。即使在( Is there a way to tell meteor a collection is static (will never change)? )中使用静态集合的可能优化时,我们也遇到了Node流程的CPU和内存使用量的巨大问题。

在我们的案例中,我们向每个客户发布了一个完全静态的15k文档集合。问题是在连接时将这些文档复制到客户端的合并盒(在内存中)基本上将节点进程带到100%CPU几乎一秒钟,并导致大量额外的内存使用。这本质上是不可扩展的,因为任何连接客户端都会使服务器瘫痪(并且同时连接会相互阻塞),并且内存使用量将在客户端数量上呈线性增长。在我们的例子中,即使传输的原始数据只有大约5MB,每个客户端也会产生额外的 ~60MB 的内存使用量。

在我们的例子中,因为集合是静态的,我们通过将所有文档作为.json文件发送来解决这个问题,该文件由nginx进行gzip压缩,然后将它们加载到匿名集合中,结果只有~~ 1MB数据传输,节点进程中没有额外的CPU或内存,加载时间更快。该集合的所有操作都是通过使用服务器上较小的出版物中的_id来完成的,从而保留了Meteor的大部分优势。这允许应用程序扩展到更多客户端。此外,由于我们的应用程序大部分是只读的,我们通过负载平衡(尽管使用单个Mongo)在nginx后面运行多个Meteor实例,进一步提高了可伸缩性,因为每个Node实例都是单线程的。

然而,在多个客户端之间共享大型可写集合的问题是需要由Meteor解决的工程问题。可能有比保留每个客户端的所有内容副本更好的方法,但这需要一些认真的思考作为分布式系统问题。目前大量CPU和内存使用问题无法扩展。

答案 2 :(得分:4)

您可以用来回答这个问题的实验:

  1. 安装测试流星:meteor create --example todos
  2. 在Webkit检查器(WKI)下运行它。
  3. 检查通过电汇移动的XHR消息的内容。
  4. 观察整个集合没有通过电线移动。
  5. 有关如何使用WKI的提示,请查看此article。它有点过时,但大多数仍然有效,特别是对于这个问题。

答案 3 :(得分:3)

现在还有一年的历史,因此我认为预先" Meteor 1.0"知识,所以事情可能会再次改变?我还在调查这个问题。 http://meteorhacks.com/does-meteor-scale.html 导致了如何扩展流星?"文章 http://meteorhacks.com/how-to-scale-meteor.html