我认为这更像是一个 MongoDB 问题,而不是一个 Meteor 问题,所以如果您对 mongo 了解很多但对 meteor 一无所知,请不要害怕。
在开发模式下运行 Meteor,但将它连接到外部 Mongo 实例而不是使用 Meteor 的捆绑实例,会导致同样的问题。这让我相信这是一个 Mongo 问题,而不是 Meteor 问题。
实际问题
我有一个 meteor该项目不断将数据添加到数据库中,并在应用程序中实时显示它们。它在开发模式下完美运行,但在构建和部署到生产环境时出现奇怪的行为。它的工作原理如下:
- 一个单独运行的小脚本收集广播 UDP 包并将它们推送到 mongo 集合中
- 然后 Meteor 应用程序发布该集合的一个子集,以便客户端可以使用它
- 客户订阅并实时更新其 View
这里的问题是,订阅似乎每 10 秒才获取一次数据,而这些 UDP 包每秒到达并被插入数据库几次。这使得应用程序表现得很奇怪
在UDP报文的收集上最为引人注意,但不仅限于此。它发生在每个订阅的集合中,即使是那些没有被外部脚本填充的集合
直接查询数据库,无论是通过 mongo shell 还是通过应用程序,都会显示文档确实按预期添加和更新。该出版物只是没有注意到并且似乎默认以 10 秒的间隔进行查询
Meteor 在 MongoDB 上使用 oplog tailing 来找出何时添加/更新/删除文档并根据此更新发布
谁比我有更多 Mongo 经验,谁可能知道问题出在哪里?
作为引用,这是死板的简单发布功能
/**
* Publishes a custom part of the collection. See {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-find} for args
*
* @returns {Mongo.Cursor} A cursor to the collection
*
* @private
*/
function custom(selector = {}, options = {}) {
return udps.find(selector, options);
}
以及订阅它的代码:
Tracker.autorun(() => {
// Params for the subscription
const selector = {
"receivedOn.port": port
};
const options = {
limit,
sort: {"receivedOn.date": -1},
fields: {
"receivedOn.port": 1,
"receivedOn.date": 1
}
};
// Make the subscription
const subscription = Meteor.subscribe("udps", selector, options);
// Get the messages
const messages = udps.find(selector, options).fetch();
doStuffWith(messages); // Not actual code. Just for demonstration
});
版本:
发展:
- Node 8.9.3
- 蒙戈 3.2.15
生产:
- Node 8.6.0
- 蒙戈 3.4.10
最佳答案
Meteor 使用两种操作模式在没有任何内置实时功能的 mongodb 之上提供实时。 poll-and-diff 和oplog-tailing
1 - Oplog-tailing
它通过读取用于同步辅助数据库的 mongo 数据库的复制日志(“oplog”)来工作。这允许 Meteor 跨多个主机提供实时更新并水平扩展。 它更复杂,并提供跨多个服务器的实时更新。
2 - 轮询和差异
poll-and-diff 驱动程序通过重复运行您的查询(轮询)并计算新旧结果之间的差异(diffing)来工作。每当同一服务器上的另一个客户端执行可能影响结果的写入时,服务器将重新运行查询。它还将定期重新运行以从其他服务器或修改数据库的外部进程中获取更改。因此,poll-and-diff 可以为连接到同一服务器的客户端提供实时结果,但它会为外部写入引入明显的延迟。 (默认值为 10 秒,这就是您遇到的情况,另请参阅附图)。
这可能会或可能不会对应用程序的用户体验产生不利影响,具体取决于应用程序(例如,不适合聊天,适合待办事项)。
这种方法很简单,并且提供易于理解的缩放特性。但是,它不能很好地适应大量用户和大量数据。由于每次更改都会导致重新获取所有结果,因此 CPU 时间和网络带宽与用户的比例为 O(N²)。不过,Meteor 会自动删除相同的查询,因此如果每个用户都执行相同的查询,则可以共享结果。
您可以通过更改 pollingIntervalMs
和 pollingThrottleMs
的值来调整 poll-and-diff。
您必须使用 disableOplog: true
选项在每个查询的基础上选择退出 oplog 拖尾。
Meteor.publish("udpsPub", function (selector) {
return udps.find(selector, {
disableOplog: true,
pollingThrottleMs: 10000,
pollingIntervalMs: 10000
});
});
附加链接:
https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908
关于node.js - Meteor MongoDB 订阅以 10 秒的间隔而不是实时传递数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48336790/