Meteor MongoDB 订阅以 10 秒为间隔而不是实时传送数据
Meteor MongoDB subscription delivering data in 10 second intervals instead of live
我认为这更像是一个 MongoDB 问题而不是一个 Meteor 问题,所以如果您对 mongo 了解很多但对 meteor 一无所知,请不要害怕。
运行 Meteor 处于开发模式,但将其连接到外部 Mongo 实例而不是使用 Meteor 的捆绑实例,会导致同样的问题。这让我相信这是一个 Mongo 问题,而不是 Meteor 问题。
实际问题
我有一个 meteor 项目,它不断获取添加到数据库的数据,并在应用程序中实时显示它们。它在开发模式下完美运行,但在构建和部署到生产环境时出现奇怪的行为。它的工作原理如下:
- 一个小脚本 运行 单独收集广播 UDP 包并将它们推送到 mongo 集合中
- Meteor 应用程序然后发布该集合的一个子集,以便客户端可以使用它
- 客户端订阅并实时更新其视图
这里的问题是订阅似乎每 10 秒才获取一次数据,而这些 UDP 包每秒到达并被推入数据库几次。这使得应用程序表现得很奇怪
在UDP报文的收集上最为引人注意,但不仅限于此。它发生在每个订阅的集合中,即使是那些没有被外部脚本填充的集合
通过 mongo shell 或通过应用程序直接查询数据库,显示确实按预期添加和更新了文档。该出版物只是没有注意到并且似乎默认以 10 秒的间隔进行查询
Meteor 在 MongoDB 上使用 oplog tailing 来找出文档何时 added/updated/removed 并根据此更新发布
有谁比我有更多 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
});
版本:
发展:
- 节点 8.9.3
- mongo 3.2.15
生产:
- 节点 8.6.0
- mongo 3.4.10
这是一个 DDP (Websocket) 心跳配置。
Meteor 实时通信和实时更新是使用 DDP(Meteor 在 SockJS 之上实现的基于 JSON 的协议)执行的。
可以更改数据并对更改做出反应的客户端和服务器。
DDP (Websocket) 协议实现所谓的 PING/PONG 消息(心跳)以保持 Websocket 活动。服务端通过Websocket向客户端发送PING报文,客户端回复PONG
默认情况下,heartbeatInterval 配置为略高于 17 秒(17500 毫秒)。
您可以使用以下命令在服务器上以毫秒为单位配置心跳时间:
Meteor.server.options.heartbeatInterval = 30000;
Meteor.server.options.heartbeatTimeout = 30000;
其他Link:
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
我认为这更像是一个 MongoDB 问题而不是一个 Meteor 问题,所以如果您对 mongo 了解很多但对 meteor 一无所知,请不要害怕。
运行 Meteor 处于开发模式,但将其连接到外部 Mongo 实例而不是使用 Meteor 的捆绑实例,会导致同样的问题。这让我相信这是一个 Mongo 问题,而不是 Meteor 问题。
实际问题
我有一个 meteor 项目,它不断获取添加到数据库的数据,并在应用程序中实时显示它们。它在开发模式下完美运行,但在构建和部署到生产环境时出现奇怪的行为。它的工作原理如下:
- 一个小脚本 运行 单独收集广播 UDP 包并将它们推送到 mongo 集合中
- Meteor 应用程序然后发布该集合的一个子集,以便客户端可以使用它
- 客户端订阅并实时更新其视图
这里的问题是订阅似乎每 10 秒才获取一次数据,而这些 UDP 包每秒到达并被推入数据库几次。这使得应用程序表现得很奇怪
在UDP报文的收集上最为引人注意,但不仅限于此。它发生在每个订阅的集合中,即使是那些没有被外部脚本填充的集合
通过 mongo shell 或通过应用程序直接查询数据库,显示确实按预期添加和更新了文档。该出版物只是没有注意到并且似乎默认以 10 秒的间隔进行查询
Meteor 在 MongoDB 上使用 oplog tailing 来找出文档何时 added/updated/removed 并根据此更新发布
有谁比我有更多 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
});
版本:
发展:
- 节点 8.9.3
- mongo 3.2.15
生产:
- 节点 8.6.0
- mongo 3.4.10
这是一个 DDP (Websocket) 心跳配置。
Meteor 实时通信和实时更新是使用 DDP(Meteor 在 SockJS 之上实现的基于 JSON 的协议)执行的。 可以更改数据并对更改做出反应的客户端和服务器。
DDP (Websocket) 协议实现所谓的 PING/PONG 消息(心跳)以保持 Websocket 活动。服务端通过Websocket向客户端发送PING报文,客户端回复PONG
默认情况下,heartbeatInterval 配置为略高于 17 秒(17500 毫秒)。
您可以使用以下命令在服务器上以毫秒为单位配置心跳时间:
Meteor.server.options.heartbeatInterval = 30000;
Meteor.server.options.heartbeatTimeout = 30000;
其他Link:
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