在索引字段和可用光标上轮询MongoDb

时间:2017-03-07 07:07:01

标签: mongodb

在MongoDb关于tailable游标的文档中,它说明了以下内容:

  

如果您的查询位于索​​引字段上,请不要使用tailable游标,而应使用常规游标。跟踪查询返回的索引字段的最后一个值。要检索新添加的文档,请使用查询条件

中索引字段的最后一个值再次查询集合

我设置查询以查找特定时间点之后的所有文档,然后在插入文档时保留返回文档。我想最简单的方法就是在我想要的时候查询_id(假设我们正在使用ObjectIds,我们是)。

由于_id是默认编入索引的,用我最后的_id继续轮询MongoDb有多糟糕并且继续询问$ gt呢?我意识到这只会在1秒内精度左右,因为ObjectIds只存储了自纪元以来的秒数,但我可以忍受,所以我假设我每秒至少要查询一次。

我想我很惊讶文档建议查询的方法(可能是在我的情况下不断),而不是保持打开游标:我会认为推送会比拉动便宜吗?

4 个答案:

答案 0 :(得分:2)

这里有一个很大的警告,我认为你可能忽略了。 Tailable游标适用于capped collections。使用上限集合可能不是一个通用的解决方案,它需要仔细规划,以确保您适当调整上限集合的大小,以考虑您的数据大小和增长。

答案 1 :(得分:1)

您想要的是收到DB中新的/更新/删除的对象的通知。没有一点诡计,mongodb是不可能的。我猜你已经读过使用tailable游标阅读oplogs,并且轮询总是绝对的最后手段。我从来没有尝试过这些,因为它们似乎有点限制(不能在共享数据库环境中使用它们)并且不可靠 - 更不用说难以设置(需要副本集)并且在未来的任何时候都容易发生变化而没有警告。例如,一个曾经流行的mongo-watch库不再用leu维护更好的替代品。)

DB“突变事件”是由某些DB实现的:Postgres实现了触发器,RethinkDB实际上将更改推送给您。如果你可以切换到像RethinkDB这样的东西 - 这将是理想的。

如果没有,我最好的建议是在数据库前放置一个服务层,所有流量必须通过该服务层。客户端应用程序可以通过套接字连接到这些服务(使用socket.io很简单 - 几乎每种语言都实现)。只要您的服务层处理更新插入删除,您就可以将这些事件发送给当前连接的任何人。

采用这种方法的限制

  • 所有数据库通信都应通过服务层。

采用这种方法的注意事项

  • 如果直接更新数据库,您将不会立即看到这些更改。您必须再次查询数据库。不是世界末日。

使用此方法的优点

  • 它比投票更好,更高效,更实时。
  • 您有一个服务层,可以为您的数据做更多业务,例如在数据发生变化时发送事件,验证数据,发送电子邮件,记录,更新其他数据源等;)
  • 这是一种适用于任何语言的范例,任何数据库。
  • 有一些轻量级框架已经实现了这种架构。 FeathersJS是我的最爱。你应该检查一下。如果你可以使用NodeJS,你至少应该从羽毛服务的工作方式中得到一些暗示。

答案 2 :(得分:0)

如果你使用tailable游标,我可以想到一些问题:

  1. 在我们到达'end'之前,你必须收到集合中的每条消息。
  2. 如果你耗尽了游标(及其await_data延迟),你必须回到起点。因此,如果应用程序重新启动,db restart等你没有任何选择,只能从头开始迭代。
  3. 除了上述内容之外,还有一些使用tailable游标的注意事项,因为它们仅适用于上限集合。

    1. 可扩展性限制与连接数。每个客户端连接都将在mongod服务器(或mongos)中添加连接线程。
    2. 上限集合具有固定的最大大小。文件不能超过这个规模。
    3. 您不能对上限集合进行分片
    4. 对上限集合中的文档进行的任何更新都不得导致文档增长。 (即并非所有$set操作都有效,且不会$push$pushAll
    5. 您可能无法明确.remove()来自上限集合的文档
    6. 您无法控制从集合中删除哪个文档。它将像一个循环队列。
    7.   

      用我最后的_id继续轮询MongoDb有多糟糕   继续询问$ gt吗?

      IMO,即使在没有更新的情况下,轮询确实会引入延迟和不必要的忙等待,但是你有很多事情可以控制。

      性能方面,只要您使用索引字段进行查询,就不会出现问题。

答案 3 :(得分:0)

提供的答案已经很好而且非常重要。但是,当我第一次阅读你的问题和问题时,或许我并不完全明白你究竟想要做什么,这听起来像是这个问题/解决方案是为 Redis <而构建的/ strong>即可。设置缓存以获取/接收信息,您可以访问它,并在需要时从缓存中删除信息,这将是一个简单的问题。

此外,数据库上的读/写操作量以及其他操作肯定会保持正常,因为您将轮询缓存。

同样,也许我没有正确理解问题,但正确设置Redis并使用它似乎是在这种情况下的方式。听起来像是为了缓存答案。