在许多客户之间共享巨大的collections时,meteor可以有多高效?

想象下面的情况:

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

  • “Somestuff”是一个拥有1000件物品的集合。

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

会发生什么:

  • 客户端上的所有Meteor.Collection将被更新,即插入转发给所有人(这意味着一个插入消息发送到1000客户端)

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

准确的说,只有插入的价值会被转发给客户,而不是整个列表?

这在现实生活中如何工作? 有这样的规模可用的基准或实验吗?

简单的答案是,只有新的数据被传送到电线上。 这是如何工作的。

Meteor服务器有三个重要部分pipe理订阅: publish函数 ,它定义了订阅提供的数据的逻辑; Mongo驱动程序 ,它监视数据库的变化; 和合并框合并所有客户的活动订阅,并通过networking发送给客户端。

发布函数

每次Meteor客户订阅一个集合时,服务器都会运行一个发布function 。 发布函数的工作是确定客户端应该拥有的文档集合,并将每个文档属性发送到合并框中。 它为每个新的订阅客户端运行一次。 您可以在发布function中放入任何您想要的JavaScript,例如使用this.userId任意复杂的访问控制。 发布函数通过调用this.addedthis.changedthis.removed将数据发送到合并框。 查看完整的发布文档以获取更多详细信息

不过,大多数发布函数并不需要赘述低级别的addedchangedremoved API。 如果发布函数返回一个Mongo游标,Meteor服务器会自动将Mongo驱动程序的输出( insertupdateremovedcallback)连接到合并框( this.addedthis.changedthis.removed )的input。 你可以在发布函数中进行所有权限检查,然后直接将数据库驱动程序连接到合并框,而不需要任何用户代码。 而当autopublish打开,即使这一点是隐藏的:服务器自动设置为每个集合中的所有文档的查询,并推入到合并框。

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

Mongo司机

Mongo驱动程序的工作是观察Mongo数据库以查看实时查询的更改。 这些查询连续运行,并通过调用addedremovedchangedcallback来更新结果。

Mongo不是一个实时数据库。 所以司机投票。 它为每个活动的实时查询保留最后查询结果的内存副本。 在每个轮询周期中,它将新的结果与先前保存的结果进行比较,计算描述差异的addedremovedchanged事件的最小集合。 如果多个调用者为相同的实时查询注册callback,则驱动程序只监视查询的一个副本,并调用每个注册的callback,结果相同。

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

合并框

合并框的工作是将所有客户端的活动发布function的结果( addedchangedremoved调用)合并为单个数据stream。 每个连接的客户端都有一个合并框。 它拥有客户端的minimongocaching的完整副本。

在你的例子中,只有一个订阅,合并框本质上是一个传递。 但更复杂的应用程序可能有多个可能重叠的订阅。 如果两个订阅都在同一个文档上设置了相同的属性,则合并框决定哪个值优先,只发送给客户端。 我们还没有公开用于设置订阅优先级的API。 目前,优先级由客户订购数据集的顺序决定。 客户所做的第一个订阅具有最高优先级,第二个订阅次高,等等。

因为合并框保存了客户端的状态,所以无论发布函数如何提供,它都可以发送最小数量的数据来保持每个客户端的最新状态。

更新会发生什么?

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

我们有1000个连接的客户端。 每个订阅了相同的实时Mongo查询( Somestuff.find({}) )。 由于每个客户端的查询都是相同的,所以驱动程序只运行一个实时查询。 有1000个活动的合并框。 并且每个客户端的发布function都注册了一个addedchangedremoved查询,并将其added到其中一个合并框中。 没有别的连接到合并框。

首先是蒙戈司机。 当其中一个客户端向Somestuff插入一个新文档时,会触发重新计算。 Mongo驱动程序重新运行Somestuff所有文档的查询,将结果与先前的内存结果进行比较,发现有一个新文档,并调用1,000个已注册的insertcallback中的每一个。

接下来,发布function。 这里几乎没有什么事情发生:1000个insertcallback中的每一个都通过调用added数据将数据推入合并框。

最后,每个合并框都会根据其客户端caching的内存副本来检查这些新属性。 在每种情况下,它都会发现这些值尚未在客户端上,并且不会影响现有值。 因此,合并框在其客户端的SockJS连接上发出DDP DATA消息,并更新其服务器端的内存副本。

总CPU成本是差异一个Mongo查询的成本,加上1,000个合并框检查客户的状态并构build新的DDP消息有效载荷的成本。 通过networking传输的唯一数据是发送到1,000个客户机中的每一个的单个JSON对象,对应于数据库中的新文档,以及从原始插入的客户机向服务器发送一个RPC消息。

优化

这是我们明确的计划。

  • 更高效的Mongo驱动程序。 我们在0.5.1中对驱动程序进行了优化 ,只对每个不同的查询运行一个观察者。

  • 不是每个数据库更改都会触发重新计算查询。 我们可以做一些自动化的改进,但是最好的方法是让开发者指定哪些查询需要重新运行。 例如,开发人员很明显,将消息插入到一个聊天室中不应使第二个聊天室中的消息的实时查询无效。

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

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

根据我的经验,使用许多客户端同时在Meteor分享巨大的集合本质上是不可行的,从版本0.7.0.1。 我会尽力解释为什么。

正如上面的post和https://github.com/meteor/meteor/issues/1821中所描述的那样,meteor服务器必须在;合并框中保留每个客户端的已发布数据的副本。 这就是允许meteor魔术发生的原因,但是也会导致任何大的共享数据库被重复地保存在节点进程的内存中。 即使在静态集合中使用可能的优化,例如( 有没有办法告诉meteor集合是静态的(永远不会改变)? ),我们遇到了一个巨大的问题,就是Node进程的CPU和内存使用情况。

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

在我们的例子中,因为集合是静态的,我们通过将所有文档作为.json文件(由nginx压缩)并将其加载到匿名集合中来解决这个问题,导致只有大约1MB的数据传输节点进程中额外的CPU或内存以及更快的加载时间。 对这个集合的所有操作都是通过使用服务器上小得多的出版物的_id来完成的,从而保留了Meteor的大部分好处。 这使得应用可以扩展到更多的客户。 另外,因为我们的应用程序大部分是只读的,所以我们通过在负载均衡(尽pipe只有一个Mongo)的情况下在nginx后面运行多个Meteor实例,进一步提高了可伸缩性,因为每个Node实例都是单线程的。

然而,在多个客户端之间共享大量可写集合的问题是meteor需要解决的一个工程问题。 对于每个客户来说,保留一份副本可能是一种更好的方法,但是这需要一些认真的思考,作为分布式系统问题。 大规模的CPU和内存使用量目前的问题不会扩大。

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

  1. 安装一个testingmeteor: meteor create --example todos
  2. 在Webkit检查器(WKI)下运行。
  3. 检查通过电线移动的XHR消息的内容。
  4. 注意整个集合没有通过电线移动。

有关如何使用WKI的提示,请查看本文 。 这是有点过时了,但大多仍然有效,特别是对于这个问题。

现在还有一年了,所以我觉得在“meteor1.0”的知识之前,可能事情又有了变化呢? 我仍然在看这个。 http://meteorhacks.com/does-meteor-scale.html导致“如何缩放meteor?”; 文章http://meteorhacks.com/how-to-scale-meteor.html