简短的回答是只有新数据才能通过网络发送。这是它的工作原理。
Meteor 服务器管理订阅的三个重要部分:发布函数,它定义订阅提供哪些数据的逻辑;Mongo 驱动程序,它监视数据库的变化;和合并框,它结合了客户端的所有活动订阅,并通过网络将它们发送给客户端。
发布功能
每次 Meteor 客户端订阅一个集合时,服务器都会运行一个
发布函数。发布功能的工作是找出其客户端应该拥有的文档集,并将每个文档属性发送到合并框。它为每个新的订阅客户端运行一次。你可以在发布函数中放入任何你想要的 JavaScript,比如使用this.userId
. this.added
发布函数通过调用和将数据发送this.changed
到
合并框中this.removed
。有关更多详细信息,请参阅
完整的发布文档。
不过,大多数发布函数不必乱用低级
added
,changed
和removed
API。如果发布函数返回一个 Mongo 游标,Meteor 服务器会自动将 Mongo 驱动程序的输出(insert
、update
和removed
回调)连接到合并框的输入(this.added
、this.changed
和this.removed
)。您可以在发布函数中预先进行所有权限检查,然后直接将数据库驱动程序连接到合并框,而无需任何用户代码,这非常简洁。并且当自动发布打开时,即使是这一点也被隐藏了:服务器会自动为每个集合中的所有文档设置一个查询,并将它们推送到合并框中。
另一方面,您不仅限于发布数据库查询。例如,您可以编写一个发布函数,该函数从 中的设备读取 GPS 位置Meteor.setInterval
,或从另一个 Web 服务轮询旧版 REST API。在这些情况下,您将通过调用低级和 DDP API 来对合并框进行added
更改。changed
removed
蒙哥司机
Mongo 驱动程序的工作是监视 Mongo 数据库中实时查询的更改。这些查询连续运行,并随着结果的变化通过调用added
、removed
和changed
回调返回更新。
Mongo 不是实时数据库。所以司机投票。它为每个活动的实时查询保留最后一个查询结果的内存副本。在每个轮询周期中,它将新结果与之前保存的结果进行比较,计算描述差异的最小集合added
、removed
和changed
事件。如果多个调用者为同一个实时查询注册回调,驱动程序只观察查询的一个副本,调用每个注册的回调并返回相同的结果。
每次服务器更新集合时,驱动程序都会重新计算该集合上的每个实时查询(Meteor 的未来版本将公开一个缩放 API,用于限制哪些实时查询在更新时重新计算。)驱动程序还以 10 秒的计时器轮询每个实时查询以捕获绕过 Meteor 服务器的带外数据库更新。
合并框
合并框的工作是将客户端所有活动发布函数的结果(added
和changed
调用removed
)合并到单个数据流中。每个连接的客户端都有一个合并框。它拥有客户端 minimongo 缓存的完整副本。
在您只有一个订阅的示例中,合并框本质上是一个传递。但更复杂的应用程序可能有多个可能重叠的订阅。如果两个订阅都在同一个文档上设置了相同的属性,则合并框会决定哪个值具有优先权并仅将其发送给客户端。我们还没有公开设置订阅优先级的 API。目前,优先级由客户端订阅数据集的顺序决定。客户端进行的第一个订阅具有最高优先级,第二个订阅次之,依此类推。
因为合并框保存客户端的状态,所以它可以发送最少的数据量以使每个客户端保持最新状态,无论发布函数为其提供什么。
更新会发生什么
所以现在我们已经为你的场景做好了准备。
我们有 1,000 个连接的客户。每个都订阅了相同的实时 Mongo 查询 ( Somestuff.find({})
)。由于每个客户端的查询都是相同的,因此驱动程序只运行一个实时查询。有 1,000 个活动的合并框。并且每个客户端的发布功能都在该实时查询上注册了一个added
, changed
, 和
removed
,该实时查询会馈送到一个合并框。没有其他东西连接到合并框。
首先是 Mongo 驱动程序。当其中一个客户端将新文档插入Somestuff
时,它会触发重新计算。Mongo 驱动程序对 中的所有文档重新运行查询Somestuff
,将结果与内存中的先前结果进行比较,发现有一个新文档,并调用 1,000 个注册的insert
回调中的每一个。
接下来是发布功能。这里几乎没有发生什么:1000 个insert
回调中的每一个都通过调用added
.
最后,每个合并框都会根据其客户端缓存的内存副本检查这些新属性。在每种情况下,它都会发现这些值尚未在客户端上,并且不会影响现有值。因此,合并框在 SockJS 与其客户端的连接上发出 DDPDATA
消息,并更新其服务器端内存中的副本。
总 CPU 成本是 diff 一个 Mongo 查询的成本,加上 1,000 个合并框检查其客户端状态并构建新的 DDP 消息有效负载的成本。通过网络传输的唯一数据是发送到 1,000 个客户端中的每一个的单个 JSON 对象,对应于数据库中的新文档,以及从进行原始插入的客户端到服务器的一条 RPC 消息。
优化
这是我们绝对计划好的。
更高效的 Mongo 驱动程序。我们
在 0.5.1 中优化了驱动程序
,使每个不同的查询只运行一个观察者。
并非每个数据库更改都应该触发重新计算查询。我们可以进行一些自动化改进,但最好的方法是使用 API,让开发人员指定哪些查询需要重新运行。例如,开发人员很明显,将消息插入一个聊天室不应使对第二个聊天室中消息的实时查询无效。
Mongo驱动、发布函数和合并框不需要运行在同一个进程中,甚至不需要运行在同一台机器上。一些应用程序运行复杂的实时查询并且需要更多 CPU 来监视数据库。其他的只有几个不同的查询(想象一个博客引擎),但可能有很多连接的客户端——这些需要更多的 CPU 用于合并框。分离这些组件将使我们能够独立地缩放每个部分。
许多数据库支持在更新行时触发的触发器并提供旧行和新行。使用该功能,数据库驱动程序可以注册触发器而不是轮询更改。