0x01.About最近在处理系统消息模块,查阅了很多实践案例,各有针对性。 首先站内消息主要包括:个人消息(评论,点赞),系统消息,订阅消息,私信。 其中,订阅区分用户群,即系统消息是一个特殊的所有人订阅的订阅消息,特点是一对多。 前三个实时性比较低,最后一个实时性高,离线状态下是私信,如果双方在线要转为聊天室,特点是一对一。 那么,接下来,该选个方案了,SQL or NoSQL? 0x02.Mysql实现首先,对于个人消息、私信("UserMessage"),一条消息插一句,Mysql跑跑没问题。 对于系统消息或订阅消息,必然不可以,假如有10万用户,一次性那么要插入10万条消息,Mysql必死。 那么就是说,要设立一个系统库("SystemMessage"),每当用户登录,就去跑跑系统库("SystemMessage"),把未读的系统库跑到个人库。 关于订阅消息就比较麻烦了,对用户分组?对消息分组? 关系型数据库处理集合问题是比较麻烦的,目前想到的结论是建立一个表("RssMessage")存储消息类型,消息索引。 下面列了大致的数据库模型: 看完这个数据库设计,我也觉得好难受,吐槽前先来想想为什么吧。 UserSystemRelation表用于记录用户读取到哪个位置的标记。 可以看到,UserMessage与SystemMessage表中,title、tid、ctime、type字段冗余了,好像也没必要, 但是从用户功能上看,当用户登陆后,查找自己站内消息,必然要用到的有:status,必然要显示的有:title、ctime,type作为用户进入消息面板后,要筛选的方式之一,这样的话,Mysql就只要跑一个表就可以完成显示给用户的最新站内消息了。 由于MessageText可能是一个大信息通知,用户查看个人消息时候,并未查看MessageText内容,所以单独放一张表。 相应处理流程
0x03.Mysql+MongoDB实现由于Mongodb是一种文档型的数据结构,所以,可以考虑把所有数据转成json直接塞给Mongodb。 基于用户的习惯,读多写少,大部分时候都是看到消息,删除、更新比较少,如果数据没更新直接读Mongodb,如果数据更新,直接删除Mongodb 这个考虑是在,用户数量很大的时候,要在"UserSystem"表里查找到用户消息比较慢的时候用,类似于吧Mongodb当缓存。 0x04.Redis实现看了Mysql下站内消息的数据库设计,我也觉得很蛋疼,临时过渡没事,但是还是NoSQL合适。 Redis自带订阅与发布系统,http://redisbook./en/latest/feature/pubsub.html 在下图展示的这个 pubsub_channels 示例中, client2 、 client5 和 client1 就订阅了 channel1 , 而其他频道也分别被别的客户端所订阅: 只要是订阅了相应地频道,就会收到频道的消息。 把用户ID作为频道,私信就是反向的频道订阅,系统消息就是所有用户的订阅,那么离线的消息呢? 1、线上用户还是存在系统或个人的哈希表里,等上线后再去读取。 在Python中,订阅发布消息(Publish)如下:
Python中,订阅监听消息(Subcribe)如下:
Redis-py的API可以看GitHub:https://github.com/andymccurdy/redis-py 这是线上用户做法。 2、线下用户看过一种做法是建立一个Redis链表,存储登陆用户,当用户登陆就直接发送,没登陆就暂存起来。 这里的话,可以用WebSocket实时监听,定期发送心跳包,如果在线直接返回Redis自带的订阅系统。 系统消息建立一个集合:
第一段标示系统信息,第二段标示日期,后面的数字标示message id。 个人消息建立一个集合:
第一段标示用户信息集合,第二段标示用户id,下一段标示消息类型为已读,后面的数字标示message id。 关于订阅消息如下:
那么你就收到小草的订阅消息,消息ID分别是 12, 13, 14, 15 还有很重要的消息数据存储,
Python创建数据库的例子就是:
参考:
本文出自 夏日小草,转载请注明出处:http:///2015/08/03/website-system-message/-by小草 2015-08-03 01:35:10 |
|
来自: 集微笔记 > 《消息系统设计与实现》