13

我正在启动一个项目,我认为由于它提供的速度和可扩展性,它特别适合 MongoDB。

我目前感兴趣的模块与实时聊天有关。如果我要在传统的 RDBMS 中执行此操作,我会将其拆分为:

  • 频道(一个频道有很多用户)
  • 用户(一个用户有一个频道但有很多消息)
  • 消息(一条消息有一个用户)

这个用例的目的,我想假设一次通常有 5 个通道处于活动状态,每个通道每秒最多处理 5 条消息。

需要快速的特定查询:

  • 获取新消息(可能基于书签、时间戳或递​​增计数器?)
  • 向频道发布消息
  • 验证用户是否可以在频道中发帖

记住 MongoDB 的文档限制为 4mb,您将如何设计架构?你的会是什么样子?有什么我应该注意的问题吗?

4

3 回答 3

3

为什么将 mongo 用于消息传递系统?无论静态存储有多快(而且 mongo 非常快),无论是 mongo 还是 db,要模拟消息队列,您都必须使用某种轮询,这不是非常可扩展或高效的。诚然,您没有做任何非常紧张的事情,但为什么不使用正确的工具来完成正确的工作呢?使用像RabbitActiveMQ这样的消息传递系统。

如果你必须使用 mongo(也许你只是想玩弄它,而这个项目是一个很好的机会呢?)我想你会有一个用户集合(每个用户对象都有一个用户队列列表听)。对于消息,您可以为每个队列收集一个集合,但是您必须轮询您感兴趣的每个队列以获取消息。最好将单个集合作为队列,因为在 mongo 中很容易对单个集合进行“in”查询,因此很容易执行“在任何队列中获取比 X 更新的所有消息”之类的事情.name 在列表 [a,b,c]”中。

您可能还考虑将您的集合设置为 mongo 封顶集合,这意味着您在设置集合时告诉 mongo,您的集合应该只包含 X 个字节或 X 个项目。添加其他项目具有先进先出的行为,这对于消息队列来说非常理想。但同样,它并不是真正的消息传递系统。

于 2010-05-29T21:19:47.740 回答
3

我在聊天项目中使用了Redis、NGINX 和 PHP-FPM。不是超级优雅,但它可以解决问题。这个难题有几个部分。

  1. 有一个非常简单的 PHP 脚本,它接收客户端命令并将它们放在一个巨大的 LIST 中。它还检查所有房间列表和用户私人列表,以查看是否有必须传递的消息。这是由一个用 jQuery 编写的客户端轮询的,每隔几秒钟就会完成一次。

  2. 有一个命令行 PHP 脚本在无限循环中运行服务器端,每秒 20 次,它检查这个列表,然后处理这些命令。脚本在脚本内存中处理谁在什么房间和权限,此信息不存储在 Redis 中。

  3. Redis 为每个房间都有一个 LIST,每个用户都有一个 LIST,作为私有队列运行。对于用户所在的每个房间,它也有多个计数器。如果用户计数器小于房间中的消息总数,那么它会获取差值并将其发送给用户。

我无法对这个解决方案进行压力测试,但至少从我的基本基准测试来看,它可能每秒可以处理数千条消息。还有机会将其移植到 Node.js 之类的东西上以提高性能。Redis 也正在成熟,并且具有一些有趣的功能,例如 Pub/Subscribe 命令,这可能很有趣,可能会消除服务器端的轮询。

我研究了基于 Comet 的解决方案,但其中许多都很复杂,文档记录不充分,或者需要我学习一种全新的语言(例如 Jetty->Java、APE->C)等......有时也可以通过代理进行交付和通过成为彗星的问题。所以这就是我坚持投票的原因。

我想你可以用 MongoDB 做类似的事情。每个房间一个集合,每个用户一个集合,然后是一个维护计数器的集合。您仍然需要编写后端守护程序或脚本来处理这些消息的去向。您还可以使用 MongoDB 的“有限集合”,它可以保持文档排序并自动清除旧消息,但是维护适当的计数器可能会很复杂。

于 2010-05-30T00:07:23.933 回答
1

1) 猿项目.org

2) http://code.google.com/p/redis/

3)在你完成所有这些之后 - 你可以将数据哑巴到 mongodb 用于记录和存储一致的数据(用户,频道)以及

于 2010-06-14T00:42:14.197 回答