问题描述
我正在启动一个项目,由于它提供的速度和可伸缩性,我认为该项目特别适合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.
需要快速查询的特定查询:
Specific queries that need to be fast:
- 获取新消息(可能基于书签,时间戳或递增计数器?)
- 向频道发布消息
- 验证用户可以在频道中发布
请记住,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.
-
有一个非常简单的PHP脚本,用于接收客户端命令并将它们放在一个庞大的LIST中.它还会检查所有房间列表和用户私人列表,以查看是否有必须发送的消息.这是由用jQuery&编写的客户端轮询的.每隔几秒钟就完成一次.
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对每个房间都有一个列表,每个用作专用队列的用户的列表.对于用户所在的每个房间,它还具有多个计数器.如果用户计数器小于房间中的总消息量,则它将获得差额并将其发送给用户.
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也日趋成熟,并具有一些有趣的功能,例如Pub/Subscribe命令,这可能很有趣,它可能会消除服务器端的轮询.
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架构设计-实时聊天的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!