本文介绍了MongoDB Schema Design - 实时聊天的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm starting a project which I think will be particularly suited to MongoDB due to the speed and scalability it affords.

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

The module I'm currently interested in is to do with real-time chat. If I was to do this in a traditional RDBMS I'd split it out into:

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

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

The the purpose of this use case, I'd like to assume that there will be typically 5 channels active at one time, each handling at most 5 messages per second.

需要快速的特定查询:

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

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

Bearing in mind that the document limit with MongoDB is 4mb, how would you go about designing the schema? What would yours look like? Are there any gotchas I should watch out for?

推荐答案

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

I used Redis, NGINX & PHP-FPM for my chat project. Not super elegant, but it does the trick. There are a few pieces to the puzzle.

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

  1. There is a very simple PHP script that receives client commands and puts them in one massive LIST. It also checks all room LISTs and the users private LIST to see if there are messages it must deliver. This is polled by a client written in jQuery & it's done every few seconds.

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

There is a command line PHP script that operates server side in an infinite loop, 20 times per second, which checks this list and then processes these commands. The script handles who is in what room and permissions in the scripts memory, this info is not stored in Redis.

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

Redis has a LIST for each room & a LIST for each user which operates as a private queue. It also has multiple counters for each room the user is in. If the users counter is less than the total messages in the room, then it gets the difference and sends it to the user.

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

I haven't been able to stress test this solution, but at least from my basic benchmarking it could probably handle many thousands of messages per second. There is also the opportunity to port this over to something like Node.js to increase performance. Redis is also maturing and has some interesting features like Pub/Subscribe commands, which might be of interest, that would possibly remove the polling on the server side possibly.

我研究了基于 Comet 的解决方案,但其中许多都很复杂,文档记录不完善,或者需要我学习一种全新的语言(例如 Jetty->Java、APE->C)等...还有交付和经历代理有时可能是 Comet 的一个问题.所以这就是我坚持投票的原因.

I looked into Comet based solutions, but many of them were complicated, poorly documented or would require me learning an entirely new language(e.g. Jetty->Java, APE->C),etc... Also delivery and going through proxies can sometimes be an issue with Comet. So that is why I've stuck with polling.

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

I imagine you could do something similar with MongoDB. A collection per room, a collection per user & then a collection which maintains counters. You'll still need to write a back-end daemon or script to handle manging where these messages go. You could also use MongoDB's "limited collections", which keeps the documents sorted & also automatically clears old messages out, but that could be complicated in maintaining proper counters.

这篇关于MongoDB Schema Design - 实时聊天的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 01:36
查看更多