资讯专栏INFORMATION COLUMN

站内消息设计与实现

A Loity / 3479人阅读

摘要:最近在处理系统消息模块,查阅了很多实践案例,各有针对性。首先站内消息主要包括个人消息评论,点赞,系统消息,订阅消息,私信。实现看了下站内消息的数据库设计,我也觉得很蛋疼,临时过渡没事,但是还是合适。


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内容,所以多带带放一张表。

相应处理流程

用户登录后,先通过"UserSystemRelation"表查询是否有新的系统消息

如果"UserSystemRelation",查找到自身uid,同步系统消息到个人消息;如果"UserSystemRelation"未查找到自身uid,直接插入"UserSystemRelation",并读取最近50条系统消息。

用户点击未读消息,获取"MessageText"",并更新状态(status)为已读。

用户通过"status"、"type",可以筛选系统消息。



0x03.Mysql+MongoDB实现

由于Mongodb是一种文档型的数据结构,所以,可以考虑把所有数据转成json直接塞给Mongodb。

基于用户的习惯,读多写少,大部分时候都是看到消息,删除、更新比较少,如果数据没更新直接读Mongodb,如果数据更新,直接删除Mongodb
的索引。

这个考虑是在,用户数量很大的时候,要在"UserSystem"表里查找到用户消息比较慢的时候用,类似于吧Mongodb当缓存。



0x04.Redis实现

看了Mysql下站内消息的数据库设计,我也觉得很蛋疼,临时过渡没事,但是还是NoSQL合适。

Redis自带订阅与发布系统,http://redisbook.readthedocs.org/en/latest/feature/pubsub.html

在下图展示的这个 pubsub_channels 示例中, client2 、 client5 和 client1 就订阅了 channel1 , 而其他频道也分别被别的客户端所订阅:

只要是订阅了相应地频道,就会收到频道的消息。

把用户ID作为频道,私信就是反向的频道订阅,系统消息就是所有用户的订阅,那么离线的消息呢?

1、线上用户

还是存在系统或个人的哈希表里,等上线后再去读取。

在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

这是线上用户做法。

2、线下用户

看过一种做法是建立一个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())))


参考:

http://redisbook.readthedocs.org/en/latest/feature/pubsub.html

http://huoding.com/2012/02/29/146

http://yijiebuyi.com/blog/faa9e68cb296d88bbc65b24dbc7b8de1.html

http://www.cnblogs.com/grenet/archive/2010/03/08/1680655.html



本文出自 夏日小草,转载请注明出处:http://homeway.me/2015/08/03/website-system-message/

-by小草

2015-08-03 01:35:10

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38713.html

相关文章

  • 站内消息设计实现

    摘要:最近在处理系统消息模块,查阅了很多实践案例,各有针对性。首先站内消息主要包括个人消息评论,点赞,系统消息,订阅消息,私信。实现看了下站内消息的数据库设计,我也觉得很蛋疼,临时过渡没事,但是还是合适。 showImg(http://77l5jp.com1.z0.glb.clouddn.com/blog/logo-sql-nosql.png); 0x01.About 最近在处理...

    Java3y 评论0 收藏0
  • 单系统站内设计概述

    摘要:也可以在凌晨系统不是那么繁忙的时候操作。总结一下少量用户设计简单,但浪费空间,冗余高中量用户设计较简单,对表的操作压力大大量用户这不是增加几个表能解决的问题 基本功能 点到点的消息传送: 用户给用户 管理员给用户 点到面的消息传送 管理员给用户群 少量用户(10-999) 对于用户非常少的情况,没有必要深入的考虑数据库的优化,采用简单的表设计: 如表message ...

    Rainie 评论0 收藏0
  • 单系统站内设计概述

    摘要:也可以在凌晨系统不是那么繁忙的时候操作。总结一下少量用户设计简单,但浪费空间,冗余高中量用户设计较简单,对表的操作压力大大量用户这不是增加几个表能解决的问题 基本功能 点到点的消息传送: 用户给用户 管理员给用户 点到面的消息传送 管理员给用户群 少量用户(10-999) 对于用户非常少的情况,没有必要深入的考虑数据库的优化,采用简单的表设计: 如表message ...

    Me_Kun 评论0 收藏0
  • 单系统站内信数据库设计思路

    摘要:第一版设计需求单用户之间通信融合了用户反馈需求数据库设计内容和收发者存在一张表中表这里一条存两次,类似邮件服务。参考群发站内信的实现群发站内信的实现续两年后,再议站内信的实现百万级用户量的站内信群发数据库设计 第一版设计 需求 :单用户之间通信(融合了用户反馈需求) 数据库设计:Message内容和收发者存在一张表中 message表: 这里一条Message存两次,类似邮件服务。...

    megatron 评论0 收藏0
  • 单系统站内信数据库设计思路

    摘要:第一版设计需求单用户之间通信融合了用户反馈需求数据库设计内容和收发者存在一张表中表这里一条存两次,类似邮件服务。参考群发站内信的实现群发站内信的实现续两年后,再议站内信的实现百万级用户量的站内信群发数据库设计 第一版设计 需求 :单用户之间通信(融合了用户反馈需求) 数据库设计:Message内容和收发者存在一张表中 message表: 这里一条Message存两次,类似邮件服务。...

    G9YH 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<