最近在处理系统消息模块,查阅了不少实践案例,各有针对性。html
首先站内消息主要包括:我的消息(评论,点赞),系统消息,订阅消息,私信。git
其中,订阅区分用户群,即系统消息是一个特殊的全部人订阅的订阅消息,特色是一对多。github
前三个实时性比较低,最后一个实时性高,离线状态下是私信,若是双方在线要转为聊天室,特色是一对一。web
那么,接下来,该选个方案了,SQL or NoSQL?redis
首先,对于我的消息、私信("UserMessage"),一条消息插一句,Mysql跑跑没问题。sql
对于系统消息或订阅消息,必然不能够,假若有10万用户,一次性那么要插入10万条消息,Mysql必死。数据库
那么就是说,要设立一个系统库("SystemMessage"),每当用户登陆,就去跑跑系统库("SystemMessage"),把未读的系统库跑到我的库。json
关于订阅消息就比较麻烦了,对用户分组?对消息分组?缓存
关系型数据库处理集合问题是比较麻烦的,目前想到的结论是创建一个表("RssMessage")存储消息类型,消息索引。数据结构
下面列了大体的数据库模型:
看完这个数据库设计,我也以为好难受,吐槽前先来想一想为何吧。
UserSystemRelation表用于记录用户读取到哪一个位置的标记。
能够看到,UserMessage与SystemMessage表中,title、tid、ctime、type字段冗余了,好像也不必,
可是从用户功能上看,当用户登录后,查找本身站内消息,必然要用到的有:status,必然要显示的有:title、ctime,type做为用户进入消息面板后,要筛选的方式之一,这样的话,Mysql就只要跑一个表就能够完成显示给用户的最新站内消息了。
因为MessageText多是一个大信息通知,用户查看我的消息时候,并未查看MessageText内容,因此单独放一张表。
因为Mongodb是一种文档型的数据结构,因此,能够考虑把全部数据转成json直接塞给Mongodb。
基于用户的习惯,读多写少,大部分时候都是看到消息,删除、更新比较少,若是数据没更新直接读Mongodb,若是数据更新,直接删除Mongodb
的索引。
这个考虑是在,用户数量很大的时候,要在"UserSystem"表里查找到用户消息比较慢的时候用,相似于吧Mongodb当缓存。
看了Mysql下站内消息的数据库设计,我也以为很蛋疼,临时过渡没事,可是仍是NoSQL合适。
Redis自带订阅与发布系统,http://redisbook.readthedocs.org/en/latest/feature/pubsub.html
在下图展现的这个 pubsub_channels 示例中, client2 、 client5 和 client1 就订阅了 channel1 , 而其余频道也分别被别的客户端所订阅:
只要是订阅了相应地频道,就会收到频道的消息。
把用户ID做为频道,私信就是反向的频道订阅,系统消息就是全部用户的订阅,那么离线的消息呢?
仍是存在系统或我的的哈希表里,等上线后再去读取。
在Python中,订阅发布消息(Publish)以下:
import redis,time queue = redis.StrictRedis(host='localhost', port=6379, db=0) channel = queue.pubsub() for i in range(100): queue.publish("test", i) time.sleep(0.1)
Python中,订阅监听消息(Subcribe)以下:
import redis,time r = redis.StrictRedis(host='localhost', port=6379, db=0) p = r.pubsub() p.subscribe('test') while True: message = p.get_message() if message: print "Subscriber: %s" % message['data']
Redis-py的API能够看GitHub:https://github.com/andymccurdy/redis-py
这是线上用户作法。
看过一种作法是创建一个Redis链表,存储登录用户,当用户登录就直接发送,没登录就暂存起来。
这里的话,能够用WebSocket实时监听,按期发送心跳包,若是在线直接返回Redis自带的订阅系统。
系统消息创建一个集合:
SADD system:2015-08-03 7 8 9 10 11
第一段标示系统信息,第二段标示日期,后面的数字标示message id。
我的消息创建一个集合:
SADD user:12345:read 1 2 3 4
第一段标示用户信息集合,第二段标示用户id,下一段标示消息类型为已读,后面的数字标示message id。
关于订阅消息以下:
SADD rss:xiaocao 12 13 14 15
那么你就收到小草的订阅消息,消息ID分别是 12, 13, 14, 15
还有很重要的消息数据存储,
HMSET message:12 title 标题 content 内容 date 2015-08-03
Python建立数据库的例子就是:
import redis,time,threading,random pool = redis.ConnectionPool(host='localhost', port=6379, db=1) rs = redis.Redis(connection_pool=pool) rs.sadd("user:123:read", "1", "2") rs.sadd("user:123:unread", "4", "5", "6") rs.sadd("system:2015-08-03", "7", "8", "9", "10", "11") rs.sadd("rss:xiaocao", "12", "13", "14", "15", "11") for i in range(15): rs.hset("message:"+str(i), "title", "title=>"+str(random.uniform(1, 99999))) rs.hset("message:"+str(i), "content","content=>"+str(time.time())) rs.hset("message:"+str(i), "date", str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())))
参考:
-by小草
2015-08-03 01:35:10