本篇主要明确消息通知系统的概念和具体实现,包括数据库设计、技术方案、逻辑关系分析等。消息通知系统是一个比较复杂的系统,这里主要分析站内消息如何设计和实现。

我们常见的消息推送渠道有以下几种:

  • 设备推送
  • 站内推送
  • 短信推送
  • 邮箱推送

我们常见的站内通知有以下几种类别:

  • 公告 Announcement
  • 提醒 Remind

    • 资源订阅提醒「我关注的资源有更新、评论等事件时通知我」
    • 资源发布提醒「我发布的资源有评论、收藏等事件时通知我」
    • 系统提醒「平台会根据一些算法、规则等可能会对你的资源做一些事情,这时你会收到系统通知」
  • 私信 Mailbox

以上三种消息有各自特点,实现也各不相同,其中「提醒」类通知是最复杂的,下面会详细讲。

数据模型设计

公告

公告是指平台发送一条含有具体内容的消息,站内所有用户都能收到这条消息。

方案一:【适合活跃用户在5万左右】

公告表「notify_announce」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //公告编号;
senderID: {type: 'string', required: true} //发送者编号,通常为系统管理员;
title: {type: 'string', required: true} //公告标题;
content: {type: ’text', required: true} //公告内容;
createdAt: {type: 'timestamp', required: true} //发送时间;

用户公告表「notify_announce_user」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //用户公告编号;
announceID: {type: 'integer'} //公告编号;
recipientID: {type: 'string', required: true} //接收用户编号;
createdAt:{type: 'timestamp', required: true} //拉取公告时间;
state: {type: 'integer', required: true} //状态,已读|未读;
readAt:{type: 'timestamp', required: true} //阅读时间;

平台发布一则公告之后,当用户登录的时候去拉取站内公告并插入notify_announce_user表,这样那些很久都没登陆的用户就没必要插入了。「首次拉取,根据用户的注册时间;否则根据notify_announce_user.createdAt即上一次拉取的时间节点获取公告」

方案二:【适合活跃用户在百万-千万左右】

和方案一雷同,只是需要把notify_announce_user表进行哈希分表,需事先生成表:notify_announce_<hash(uid)>。

用户公告表「notify_announce_<hash(uid)>」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //用户公告编号;
announceID: {type: 'integer'} //公告编号;
recipientID: {type: 'string', required: true} //接收用户编号;
createdAt:{type: 'timestamp', required: true} //拉取公告时间;
state: {type: 'integer', required: true} //状态,已读|未读;
readAt:{type: 'timestamp', required: true} //阅读时间;

提醒

提醒是指「我的资源」或「我关注的资源」有新的动态产生时通知我。提醒的内容无非就是:
「someone do something in someone's something」
「谁对一样属于谁的事物做了什么操作」

常见的提醒消息例子,如:
XXX 关注了你 - 「这则属于资源发布提醒」
XXX 喜欢了你的文章 《消息通知系统模型设计》 - 「这则属于资源发布提醒」
你喜欢的文章《消息通知系统模型设计》有新的评论 - 「这则属于资源订阅提醒」
你的文章《消息通知系统模型设计》已被加入专题 《系统设计》 - 「这则属于系统提醒」
小明赞同了你的回答 XXXXXXXXX -「这则属于资源发布提醒」

最后一个例子中包含了消息的生产者(小明),消息记录的行为(赞同),行为的对象(你的回答内容)

分析提醒类消息的句子结构:
someone = 动作发起者,标记为「sender」
do something = 对资源的操作,如:评论、喜欢、关注都属于一个动作,标记为「action」
something = 被作用对象,如:一篇文章,文章的评论等,标记为「object」

someone's = 动作的目标对象或目标资源的所有者,标记为「objectOwner」

总结:sender 和 objectOwner 就是网站的用户,object 就是网站资源,可能是一篇文章,一条文章的评论等等。action 就是动作,可以是赞、评论、收藏、关注、捐款等等。

提醒设置

提醒通常是可以在「设置-通知」里自定义配置的,用户可以选择性地「订阅」接收和不接收某类通知。

呈现在界面上是这样的:

通知设置我发布的 publish被 评论    是/否 通知我被 收藏    是/否 通知我被 点赞    是/否 通知我被 喜欢    是/否 通知我被 捐款    是/否 通知我我订阅的 follow有 更新   是/否 通知我被 评论   是/否 通知我

订阅

一般系统默认是订阅了所有通知的。系统在给用户推送消息的时候必须查询通知「订阅」模块,以获取某一事件提醒消息应该推送到哪些用户。
也就是说「事件」和「用户」之间有一个订阅关系。

那么接下来我们分析下「订阅」有哪些关键元素:

比如我发布了一篇文章,那么我会订阅文章《XXX》的评论动作,所以文章《XXX》每被人评论了,就需要发送一则提醒告知我。

分析得出以下关键元素:

  • 订阅者「subscriber」
  • 订阅的对象「object」
  • 订阅的动作「action」
  • 订阅对象和订阅者的关系「objectRelationship」

什么是订阅的目标关系呢?

拿知乎来说,比如我喜欢了一篇文章,我希望我订阅这篇文章的更新、评论动作。那这篇文章和我什么关系?不是所属关系,只是喜欢。

  • objectRelationship = 我发布的,对应着 actions = [评论,收藏]
  • objectRelationship = 我喜欢的,对应着 actions = [更新,评论]

讲了那么多,现在来构建「提醒」的数据结构该吧!

提醒表「notify_remind」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //主键;
remindID: {type: 'string', required: true} //通知提醒编号;
senderID: {type: 'string', required: true} //操作者的ID,三个0代表是系统发送的;
senderName: {type: 'string’, required: true} //操作者用户名;
senderAction: {type: 'string', required: true} //操作者的动作,如:赞了、评论了、喜欢了、捐款了、收藏了;
objectID: {type: 'string', required: true}, //目标对象ID;
object: {type: 'string', required: false}, //目标对象内容或简介,比如:文章标题;
objectType: {type: 'string', required: true} //被操作对象类型,如:人、文章、活动、视频等;
recipientID: {type: 'string’} //消息接收者;可能是对象的所有者或订阅者;
message: {type: 'text', required: true} //消息内容,由提醒模版生成,需要提前定义;
createdAt:{type: 'timestamp', required: true} //创建时间;
status:{type: 'integer', required: false} //是否阅读,默认未读;
readAt:{type: 'timestamp', required: false} //阅读时间;

假如:特朗普关注了金正恩,以下字段的值是这样的

senderID = 特朗普的ID
senderName = 特朗普
senderAction = 关注
objectID = 金正恩的ID
object = 金正恩
objectType = 人
recipientID = 金正恩的ID
message = 特朗普关注了金正恩这种情况objectID 和 recipientID是一样的。

这里需要特别说下消息模版,模版由「对象」、「动作」和「对象关系」构成唯一性。

通知提醒订阅表「notify_remind_subscribe」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //订阅ID;
userID: {type: 'string', required: true},//用户ID,对应 notify_remind 中的 recipientID;
objectType: {type: 'string', required: true} //资源对象类型,如:文章、评论、视频、活动、用户;
action: {type: 'string', required: true} //资源订阅动作,多个动作逗号分隔如: comment,like,post,update etc.
objectRelationship: {type: 'string', required: true} //用户与资源的关系,用户发布的published,用户关注的followed;
createdAt:{type: 'timestamp', required: true} //创建时间;

特别说下「objectRelationship」字段的作用,这个字段用来区分「消息模版」,为什么呢?因为同一个「资源对象」和「动作」会有两类订阅者,一类是该资源的Owner,另一类是该资源的Subscriber,这两类人收到的通知消息内容应该是不一样的。

聚合

假如我在抖音上发布了一个短视频,在我不在线的时候,被评论了1000遍,当我一上线的时候,应该是收到一千条消息,类似于:「* 评论了你的文章《XXX》」? 还是应该收到一条信息:「有1000个人评论了你的文章《XXX》」?

当然是后者更好些,要尽可能少的骚扰用户。

消息推送

是不是感觉有点晕了,还是先上一张消息通知的推送流程图吧:

订阅表一共有两张噢,一张是「通知订阅表」、另一张是用户对资源的「对象订阅表」。
具体实现就不多讲了,配合这张图,理解上面讲的应该不会有问题了。

私信

通常私信有这么几种需求:

  • 点到点:用户发给用户的站内信,系统发给用户的站内信。「1:1」
  • 点到多:系统发给多个用户的站内信,接收对象较少,而且接收对象无特殊共性。「1:N」
  • 点到面:系统发给用户组的站内信,接收对象同属于某用户组之类的共同属性。「1:N」
  • 点到全部:系统发给全站用户的站内信,接收对象为全部用户,通常为系统通知。「1:N」

这里主要讲「点到点」的站内信。

私信表「notify_mailbox」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //编号;
dialogueID: {type: 'string', required: true} //对话编号;
senderID: {type: 'string', required: true} //发送者编号;
recipientID: {type: 'string', required: true} //接收者编号;
messageID: {type: 'integer', required: true} //私信内容ID;
createdAt:{type: 'timestamp', required: true} //发送时间;
state: {type: 'integer', required: true} //状态,已读|未读;
readAt:{type: 'timestamp', required: true} //阅读时间;

Inbox

私信列表
select * from notify_inbox where recipientID="uid" order by createdAt desc对话列表
select * from notify_inbox where dialogueID=“XXXXXXXXXXXX” and (recipientID=“uid” or senderID="uid") order by createdAt asc

私信回复时,回复的是dialogueID

Outbox

私信列表
select * from notify_inbox where senderID="uid" order by createdAt desc对话列表
select * from notify_inbox where dialogueID=“XXXXXXXXXXXX” and (senderID=“uid” or recipientID="uid") order by createdAt asc

私信内容表「notify_inbox_message」
表结构如下:

id: {type: 'integer', primaryKey: true, autoIncrement:true} //编号;
senderID: {type: 'string', required: true} //发送者编号;
content: {type: 'string', required: true} //私信内容;
createdAt:{type: 'timestamp', required: true}

消息通知系统模型设计 1相关推荐

  1. 消息通知系统模型设计

    本篇主要明确消息通知系统的概念和具体实现,包括数据库设计.技术方案.逻辑关系分析等.消息通知系统是一个比较复杂的系统,这里主要分析站内消息如何设计和实现. 我们常见的消息推送渠道有以下几种: 设备推送 ...

  2. 如何实现消息通知系统

    本篇主要明确消息通知系统的概念和具体实现,包括数据库设计.技术方案.逻辑关系分析等.消息通知系统是一个比较复杂的系统,这里主要分析站内消息如何设计和实现. 我们常见的消息推送渠道有以下几种: 设备推送 ...

  3. Redis消息通知系统的实现

    Redis消息通知系统的实现 Posted on 2012-02-29 by 老王 http://huoding.com/2012/02/29/146 最近忙着用Redis实现一个消息通知系统,今天大 ...

  4. JAVA社交平台项目第四天 消息通知系统

    第4章 - 消息通知系统 学习目标: 了解消息通知系统的业务场景 了解消息通知和即时通讯区别 实现消息通知微服务的基本功能 实现文章订阅和群发消息 实现文章点赞和点对点消息 了解基于数据库实现的通知系 ...

  5. 消息通知系统详解2---后端设计

    消息通知系统详解1-通讯方式 消息通知系统详解2-后端设计 消息通知系统详解3-Netty 消息通知系统详解4-整合Netty和WebSocket 目录 整体设计 上线登录后向系统索取 在线时系统向接 ...

  6. 消息通知系统详解1---通讯方式

    消息通知系统详解1-通讯方式 消息通知系统详解2-后端设计 消息通知系统详解3-Netty 消息通知系统详解4-整合Netty和WebSocket 目录 什么是消息通知系统 系统特性 通讯方式 短连接 ...

  7. 如何设计一个公司级别的消息通知系统?

    实际场景 早上买早点,扫码下单,用户在微信中会收到下单成功的服务通知. 扫码出地铁后,手机会收到APP支付通知. 微信.支付宝.刷卡消费后,手机会收到短信通知. 在海底捞吃完火锅,扫结账小票上的开票二 ...

  8. Laravel 论坛系统之消息通知功能

    消息通知 这篇文章我们来开发消息通知功能,当话题有新回复时,我们将通知作者『你的话题有新回复,请查看』类似的信息. Laravel 的消息通知系统 Laravel 自带了一套极具扩展性的消息通知系统, ...

  9. 消息通知系统设计六要素

    无论是 B 端还是 C 端产品,消息通知系统都是一个很基础且必不可少的模块,而产品经理要设计一个完整的消息通知系统并不难,只需要遵守好消息通知系统设计的六要素即可. 消息通知六要素 通知消息围绕在我们 ...

最新文章

  1. 开发log4j配置_Spring 使用 Log4J 记录日志
  2. MVC框架内容-视图
  3. 工作能力强的人有哪些共同特征?
  4. Mysql查询的一些操作(查表名,查字段名,查当月,查一周,查当天)
  5. 打印函数如何适应不同的打印机
  6. 反向传播BP 算法之一种直观的解释
  7. webservice 返回对象 java_JAVA 调用webservice不同返回值类型的方法
  8. BZOJ 3910 并查集+线段树合并
  9. E20170830-mk
  10. 没有找到**.dll的解决方案
  11. ListView中嵌套checkbox
  12. 双系统启动修复完整解决方案
  13. 记一次失败的小米前端面试经历
  14. 2023秋招大厂经典面试题及答案整理归纳(201-220)校招必看
  15. Github上设置小图标/小徽章
  16. linux v4l2系统详解,Linux摄像头驱动学习之:(一)V4L2_框架分析
  17. 英语c开头语言,C开头的英语谚语大全带汉语
  18. 计算机方面特长特招进北大,机器人特长生保送进北大!
  19. break 跳出两层甚至多层 for 循环
  20. android面试(个人)简历

热门文章

  1. 专访iDST华先胜:城市大脑,对城市的全量、实时认知和搜索
  2. 百度霸屏效果该如何实现
  3. 【CodeForces - 603E】Pastoral Oddities
  4. NYOJ869---切蛋糕
  5. 易语言加密数据之后无法解密数据的问题
  6. 博科光纤交换机操作手册之一
  7. 让人哀惋叹息的荷兰人
  8. 虚拟机连接本地wifi网络
  9. 鸿蒙os 2.0应用商店,鸿蒙版京东App已在华为应用商城上架 包含HarmonyOS服务
  10. TCP-IP详解笔记3