作者:guang19

使用过简书,知乎或 b 站的小伙伴应该都有这样的使用体验:当有其他用户关注我们或者私信我们的行为时,我们会收到相关的消息。 虽然这些功能看上去简单,但其背后的设计是非常复杂的,几乎是一个完成的系统,可以称之为 站内消息系统

我以 b 站举例(个人认为 b 站的消息系统是我见过的非常完美的,UI 也最为人性化的):

b站站内消息

可以看到 b 站把消息大致分为了三类:

  1. 系统推送的通知(System Notice);

  2. 回复、@、点赞等用户行为产生的提醒(Remind);

  3. 用户之间的私信(Chat)。

这样设计不仅分类明确,且处于同一个主体的事件提醒还会做一个聚合,极大的提高了用户体验,不让用户收到太多分散的消息。

举个例子:比如你在某个视频或某篇文章下发表了评论,有 100 个人给你的评论点了赞,那么你希望消息页面呈现的是一个一个用户给你点赞的提醒,还是像以下聚合之后的提醒:

消息的聚合

我相信你大概率会选择后者。

我认为对于很多应用来说,这样的设计都是非常合理的,接下来我写写我对于消息系统的设计。

系统通知(System Notice)

系统通知一般是由后台管理员发出,然后指定某一类(全体,个人等)用户接收。基于此设想,可以把系统通知大致分为两张表:

  1. t_manager_system_notice(管理员系统通知表) :记录管理员发出的通知 ;

  2. t_user_system_notice(用户系统通知表) : 存储用户接受的通知。

t_manager_system_notice 结构如下:

t_user_system_notice 结构如下:

当管理员发布一条通知后,将通知插入 t_manager_system_notice 表中,然后系统定时的从 t_manager_system_notice 表中拉取通知,然后根据通知的 type 将通知插入 t_user_system_notice 表中。

如果通知的 type 是 single 的,那就只需要插入一条记录到 t_user_system_notice 中。如果是全体用户,那么就需要将一个通知批量根据不同的用户 ID 插入到 t_user_system_notice 中,这个数据量就需要根据平台的用户量来计算。

举个例子: 管理员 A 发布了一个活动的通知,他需要将这个通知发布给全体用户,当拉取时间到来时,系统会将这一条通知取出。随后系统到用户表中查询选取所有用户的 ID,然后将这一条通知的信息根据所有用户的 ID,批量插入 t_user_system_notice 中。用户需要查看系统通知时,从 t_user_system_notice 表中查询就行了。

注意:

  1. 因为一次拉取的数据量可能很大,所以两次拉取的时间间隔可以设置的长一些。

  2. 拉取 t_manager_system_notice 表中的通知时,需要判断 state,如果已经拉取过,就不需要重复拉取, 否则会造成重复消费。

  3. 当一条通知需要发布给全体用户时,我们应该考虑到用户的活跃度。因为如果有些用户长期不活跃, 我们还将通知推送给他(她),这显然会造成空间的浪费。 所以在选取用户 ID 时,我们可以将用户上次 登录的时间与推送时间做一个比较,如果用户一年未登陆或几个月未登录,我们就不选取其 ID,进而避免 无谓的推送。

  4. 有的小伙伴可能有疑问: 某条通知已经被拉取过的话,在其后注册的用户是不是不能再接收到这条通知? 是的。但如果你想将已拉取过的通知推送给那些后注册的用户,也不是特别大的问题。 只需要再写一个定时任务,这个定时任务可以将通知的 push_time 与用户的注册时间比较一下,重新推送即可。

以上就是系统通知的设计了,接下来再看看较难的提醒类型的消息。

事件提醒(EventRemind)

之所以称提醒类型的消息为事件提醒,是因为此类消息均是通过用户的行为产生的,如下:

  • xxx 在某个评论中@了你;

  • xxx 点赞了你的文章;

  • xxx 点赞了你的评论;

  • xxx 回复了你的文章;

  • xxx 回复了你的评论。

诸如此类事件,我们以单词 action 形容不同的事件(点赞,回复,at)。 可以看到除了事件之外,我们还需要了解用户是在哪个地方产生的事件,以便当我们收到提醒时, 点击这条消息就可以去到事件现场,从而增强用户体验,我以事件源 source 来形容事件发生的地方。

  • 当 action 为点赞,source 为文章时,我就知道:有用户点赞了我的某篇文章;

  • 当 action 为点赞,source 为评论时,我就知道:有用户点赞了我的某条评论;

  • 当 action 为@(at), source 为评论时,我就知道:有用户在某条评论里@了我;

  • 当 action 为回复,source 为文章时,我就知道:有用户回复了我的某篇文章;

  • 当 action 为回复,source 为评论时,我就知道:有用户回复了我的某条评论;

由此可以设计出事件提醒表 t_event_remind,其结构如下:

消息聚合

消息聚合只适用于事件提醒,以聚合之后的点赞消息来说:

  • 100 人 {点赞} 了你的 {文章 ID = 1} :《A》;

  • 100 人 {点赞} 了你的 {文章 ID = 2} :《B》;

  • 100 人 {点赞} 了你的 {评论 ID = 3} :《C》;

聚合之后的消息明显有两个特征,即:action 和 source type,这是系统消息和私信都不具备的, 所以我个人认为事件提醒的设计要稍微比系统消息和私信复杂。

如何聚合?

稍稍观察下聚合的消息就可以发现:某一类的聚合消息之间是按照 source type 和 source id 来分组的, 因此我们可以得出以下伪 SQL:

SELECT * FROM t_event_remind WHERE recipient_id = 用户ID
AND action = 点赞 AND state = FALSE GROUP BY source_id , source_type;

当然,SQL 层面的结果集处理还是很麻烦的,所以我的想法先把用户所有的点赞消息先查出来, 然后在程序里面进行分组,这样会简单不少。

拓展

其实还有一种设计提醒表的做法,即按业务分类,不同的提醒存入不同的表,这样可以分为:

  1. 点赞提醒表

  2. 回复提醒表

  3. at(@)提醒表。

我认为这种设计比第一种的更松耦合,不必所有类型的提醒都挤在一张表里,但是这也会带来表数量的膨胀。 所以各位小伙伴可以自行选择方案。

私信

站内私信一般都是点到点的,且要求是实时的,服务端可以采用 Netty 等高性能网络通信框架完成请求。 我们还是以 b 站为例,看看它是怎么设计的:

站内消息系统的设计

b 站的私信部分可以分为两部分:

  1. 左边的与不同用户的聊天室;

  2. 与当前正在对话的用户的对话框,显示了当前用户与目标用户的所有消息。

按照这个设计,我们可以先设计出聊天室表 t_private_chat,因为是一对一,所以聊天室表会包含对话的两个用户的信息:

这里 user1_id 和 user2_id 代表两个用户的 ID,并无特定的先后顺序。

接下来是私信表 t_private_message 了,私信自然和所属的聊天室有联系,且考虑到私信可以在记录中删除(删除了只是不显示记录,但是对方会有记录,撤回才是真正的删除),就还需要记录私信的状态,以下是我的设计:

消息设置

消息设置一般都是针对提醒类型的消息的,且肯定是由用户自己设置的。所以我想到一般有以下设置选项:

  1. 是否开启点赞提醒;

  2. 是否开启回复提醒;

  3. 是否开启@提醒;

下面是 b 站的消息设置:

消息设置

可以看到 b 站还添加了陌生人选项,也就是说如果给你发送私信的用户不是你关注的用户,那么视之为陌生人私信,就不接受。

以下是我对于消息设置的设计:

总结

以上就是我对于整个站内消息系统的大概设计了,我参考了很多文章的内容以及很多网站的设计,但实际项目的需求肯定与我所介绍的有很多出入,所以各位小伙伴可以酌情参考。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

以 B 站为例,聊聊站内消息系统的设计相关推荐

  1. [转贴]现在在做一个WEB的站内消息系统,从工具栏位置弹出一徐徐上升的窗口...

    现在在做一个WEB的站内消息系统, 想在用户登陆时, 如果有未读短消息 则从工具栏位置弹出一徐徐上升的窗口 显示提醒信息! <script language="JavaScript&q ...

  2. 直播软件源码开发,直播间内消息系统的实现

    在直播软件源码开发过程中,消息系统是非常关键的,无论是直播间内的消息还是平台内的消息,都关系着用户的使用体验,所以今天我们先用一个简单的"拉"模型搭建一个简单的直播间消息系统. 基 ...

  3. 城市中心区综合交通枢纽规划策略:以深圳市西丽高铁站为例

    " 写在前面: 综合交通枢纽是反映交通系统运行效率和服务品质的关键载体.在高密度城市中心区新建大型综合交通枢纽是一个非常复杂的系统工程,需要重点考虑站城融合.交通可持续发展.大客流组织以及多 ...

  4. b站 前端构架_技术干货:哔哩哔哩(B站)功能框架图 ——以B站为例分析面对秋招必须要掌握的前后端...

    本次夏令营知了堂项目经理以B站为原型,带着大家熟悉了软件的开发流程及还原了部分功能模块.现在就将B站功能架构图及前后端技术栈给大家.同时从以B站技术为例给大家分析作为应届毕业生,面对秋季校招时必须要掌 ...

  5. 站内信息 php,站内消息_php教程

    php代码class MessageModel extends Model { public $_fields = array( //字段 'id' => 'Id', 'title' => ...

  6. html站内消息列表,WebSocket实现站内消息实时推送

    关于WebSocket WebSocket是HTML5 开始提供的一种在单个TCP连接上进行全双工通讯的协议.什么是全双工?就是在同一时间可以发送和接收消息,实现双向通信,比如打电话.WebSocke ...

  7. Django站内消息通知

    1.安装Notifications 站内通知使用django-notifications-hq第三方库.执行如下命令安装django-notifications-hq: pip install dja ...

  8. mysql群发消息_分享网站群发站内信数据库表设计

    本文和大家分享一下网站站内信实现表设计的功能.需要的朋友可以参考下. "站内信"不同于电子邮件,电子邮件通过专门的邮件服务器发送.保存.而"站内信"是系统内的消 ...

  9. 网站群发站内信数据库表设计

    "站内信"不同于电子邮件,电子邮件通过专门的邮件服务器发送.保存.而"站内信"是系统内的消息,说白了,"站内信"的实现,就是通过数据库插入记 ...

最新文章

  1. android -volley-请求数据
  2. 通用存储过程分页---(测试能用的请放心试用)
  3. 异地多活场景下的数据同步之道 | 珍藏版
  4. FORTRAN学习记录(持续更新)
  5. python读取写入文件_Python文件读写保存操作
  6. win10计算机无法复制文件,Win10系统下移动、复制、删除文件需要管理员权限的解决方法...
  7. CodeProject每日精选: Progress controls 进度条
  8. Nand Flash数据存储单元的整体架构
  9. 详解Python中的序列解包(2)
  10. C/C++ 远程开发 - NetBeans IDE 教程 -转
  11. div搜索框与按钮不在一行_这款漫画资源搜索软件,堪称二次元迷的必备神器!...
  12. HTML资源嗅探,scrapy-2 嗅探网站,解析HTML
  13. Win7——无Internet访问权限
  14. 解决:The server time zone value ‘�й���׼ʱ��‘ is unrecognized or represents more than one time zone报错问题
  15. Hystrix Dashboard
  16. 解决Maven安装Tomcat插件后,使用出现8080端口占用的问题
  17. XenApp6.0 部署之 二 配置XenApp Server
  18. mysql diff函数_MYSQL中 的datediff、timestampdiff函数
  19. 易语言Excel工作簿方法
  20. PHP PDO 连接SQLSErver,php pdo连接sqlserver配置

热门文章

  1. Django +nginx + uwsgi + daphne部署
  2. 部署thinkphp5框架的php,三、部署ThinkPHP5框架
  3. linux将所有文件生成lst_10行Python代码自动清理电脑内重复文件,解放双手!
  4. ai合成迪丽热巴下海_丽热巴被富家哥求婚,男方坚持示爱九个月,当众下跪赠女方豪车...
  5. mysql 1033 frm_MySQL ERROR 1033 (HY000): Incorrect information in file. 处理一例
  6. [Android]解决Fragment无法使用android:onClick属性
  7. 数据结构之顺序循环队列
  8. (软件工程复习核心重点)第一章软件工程概论-第三节:软件生命周期
  9. (计算机组成原理)第五章中央处理器-第五节2:指令流水线影响因素和分类及多发技术
  10. 3-5:类与对象中篇——默认成员函数之运算符重载