Meteor MongoDB订阅以10秒的间隔提供数据而不是实时数据

Sup*_*pen 3 mongodb node.js meteor

我相信这更像是一个MongoDB问题,而不是一个流星问题,所以如果你对mongo有很多了解,但对流星一无所知,不要害怕.

在开发模式下运行Meteor,但将其连接到外部Mongo实例而不是使用Meteor的捆绑实例,会导致同样的问题.这让我相信这是一个Mongo问题,而不是流星问题.


实际问题

我有一个流星项目,它不断地将数据添加到数据库中,并在应用程序中实时显示它们.它在开发模式下完美运行,但在构建和部署到生产时具有奇怪的行为.它的工作原理如下:

  • 一个单独运行的小脚本收集广播UDP包并将它们推送到mongo集合中
  • 然后,Meteor应用程序发布此集合的子集,以便客户端可以使用它
  • 客户端订阅并实时更新其视图

这里的问题是订阅似乎只获得大约每10秒一次的数据,而这些UDP包到达并每秒数次被推入数据库.这使得应用程序表现得很奇怪

UDP消息的收集最为明显,但不限于此.它发生在订阅的每个集合中,即使那些没有被外部脚本填充的集合也是如此

通过mongo shell或通过应用程序直接查询数据库,表明文档确实按照预期添加和更新.该出版物没有注意到,并且似乎默认以10秒的间隔查询

Meteor使用MongoDB上的oplog尾部来查找何时添加/更新/删除文档并基于此更新出版物

有没有比我更多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);
}
Run Code Online (Sandbox Code Playgroud)

和订阅它的代码:

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
});
Run Code Online (Sandbox Code Playgroud)

版本:

发展:

  • 节点8.9.3
  • 蒙戈3.2.15

生产:

  • 节点8.6.0
  • 蒙戈3.4.10

Bad*_*bet 6

Meteor使用两种操作模式在mongodb之上提供实时,而mongodb没有任何内置的实时功能.poll-and-diffoplog-tailing

1 - Oplog-tailing

它的工作原理是读取mongo数据库的复制日志,它用于同步辅助数据库('oplog').这使得Meteor可以跨多个主机提供实时更新并进行水平扩展.它更复杂,并提供跨多个服务器的实时更新.

2 - 民意调查和差异

poll-and-diff驱动程序通过重复运行查询(轮询)并计算新旧结果(差异)之间的差异来工作.每次同一服务器上的另一个客户端执行可能影响结果的写入时,服务器将重新运行查询.它还将定期重新运行,以从其他服务器或修改数据库的外部进程中获取更改.因此,poll-and-diff可以为连接到同一服务器的客户端提供实时结果,但它会为外部写入带来明显的延迟.(默认值为10秒,这就是您所遇到的情况,另请参阅附图).

在此输入图像描述 在此输入图像描述

这可能会也可能不会对应用程序UX产生不利影响,具体取决于应用程序(例如,聊天不好,待办事项罚款).

这种方法很简单,并且易于理解缩放特性.但是,它不能很好地适应大量用户和大量数据.由于每次更改都会导致重新获取所有结果,因此CPU时间和网络带宽会与用户缩放O(N²).但是,Meteor会自动重复删除相同的查询,因此如果每个用户执行相同的查询,则可以共享结果.

您可以通过更改pollingIntervalMs和的值来调整poll-and-diff pollingThrottleMs.

您必须使用disableOplog: true选项在每个查询的基础上选择退出oplog尾部.

Meteor.publish("udpsPub", function (selector) {
  return udps.find(selector, {
    disableOplog: true,
    pollingThrottleMs: 10000, 
    pollingIntervalMs: 10000
  });
});
Run Code Online (Sandbox Code Playgroud)

其他链接:

https://medium.baqend.com/real-time-databases-explained-why-meteor-rethinkdb-parse-and-firebase-dont-scale-822ff87d2f87

https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908

如何使用pollingThrottle和pollingInterval?