如何设计一个消息中心

简介:

如今的内容型产品,不管提供的是什么类型的内容,在其主功能之外,不可避免的会有另一个十分重要的功能——消息中心。

而无论是信息流、论坛、信箱,还是私聊、群聊、通知,推拉模型是内容型(包括:社交型)产品架构的核心。做出正确选择的关键在于对产品形态和系统组件清晰的认识。

今天我们将重心放在消息中心上,聊一聊如何设计一个消息中心。

需求分析

消息中心通常会有两个功能(如下图所示):

  1. 用户通知(点赞、评论、关注、@等)
  2. 官方通知

接下来我们将会对这两类通知进行一个简单的抽象。

首先,可以确定的是,对于用户通知,每个用户都不一样(我的点赞列表和你的点赞列表肯定是不一样的),因此对于每个人我们都需要维护一个「收件箱」。

当 A 点赞了 B 的内容,后端系统在收到了这一个点赞消息后,会将点赞信息写入 B 的 「收件箱」,并标明这是 A 在 xxx 时点赞的 xxx 内容。这是一个系统将消息 推送 给 B 的过程。

而对于官方通知,每个人(几乎)都是一样的(用户有可能设置了屏蔽,系统也可能指定了发送人群),并且官方通知是由系统自然下发的,因此对于系统来说需要维护一个系统「发件箱」。

发件箱维护了官方想给用户的通知,每次打开消息中心时,用户都会主动来系统「拉取」官方最新的消息,并和用户自己的「收件箱」里的官方通知进行比较,以确认是否已读该条通知。这是一个用户主动从系统「拉取」通知的过程。

推拉模型

其实到这里就已经点出了这两个场景背后的一套模型——推拉模型。而之所以在这两种场景选择不同的运行机制,其实背后牵扯到的是读写扩散的问题。

推模型

先看推模型,对于任何一个内容创作者来说,最开心的事情莫过于打开软件会有一堆点赞/评论的小红点。对于大 V 来说,打开 App 查看点赞消息的频率根本比不过别人给你点赞的频率,这是一个很典型的读少写多的场景。每当有一个用户点赞该大 V 时,都会将索引信息(一般为内容 ID、类型、发表时间等索引数据)写到用户的收件箱中。

  • 优点:读很轻。仅需要读取消息列表即可。
  • 缺点:写很重。一旦用户的内容质量很高,可能会收到大量的点赞/评论,会有大量的写入操作。

拉模型

再看拉模型,以官方通知为例,一般官方通知是由运营人员发布的,一个月可能也不会有几条,但是每次用户进入 App 时都会看看是否有新的官方通知进来,这是一个很典型的读多写少的场景。

  • 优点:写很轻,节省空间。系统只需维护一个属于自己的消息列表即可。
  • 缺点:读很重,计算量大。假设可以发送官方通知的生产者较多(例如淘宝里的一系列官方业务),则每次都需要从这些消息生产者里拉取最新的内容。

流程设计

用户通知

对于用户通知,流程设计如下:

对于该流程,有几点需要注意的:

异步发送

当用户出发了点赞/关注/评论行为时,被点赞/评论/关注的用户,其实不需要立即感知,因此也不需要立即将互动信息写入该用户的收件箱中,因此可以考虑以消息队列的方式通知出去,缓解系统压力。

缓存前置

写入消息时,如果直接写入用户收件箱,可能会导致用户在请求消息列表时,将请求全部打到 DB,造成系统故障,因此通常会在更新用户收件箱时双写用户缓存。

官方通知

相较于用户通知,官方通知由于引入官方运营这一角色,操作上会稍微复杂一些(如上图所示),因此整个系统的设计也会稍微复杂一些。

官方运营发送通知到「发件箱」中,「发件箱」中保留所有在线的通知列表。用户查看通知列表时,从官方「发件箱」中获取到未读通知,从自己的「收件箱」中查询历史通知。即:

  1. 运营写发件箱
  2. 用户读发件箱
  3. 用户写收件箱

流程示意图如下

官方运营在运营后台进行通知的编辑和发布,发布的通知更新到数据库中进行持久化存储。(这里选择 mysql 数据库进行数据持久化,下一章节将会提到)

通知发生变更时,会发送通知变更消息。基于该消息更新单条通知的缓存,并更新官方发件箱列表(供前台查询)。

用户查看通知列表时,若为第一页,需要从官方发件箱队列查看是否有未读的通知。

若有未读通知,则和历史通知第一页合并,返回给用户。同时异步写入用户的收件箱中。

持久化方案

说完了核心的业务流程后,接下来要面临的问题就是,数据存在哪?

上文有提到会将官方通知的发件箱利用 mysql 持久化,因为官方通知的数量较少,且官方通知是一个拉模型,重读轻写,压力多半由缓存来扛,所以底层数据存储在 mysql 中并无大碍。

重难点主要在用户的「收件箱」。

之前有提过,用户收件箱的逻辑是一个重写轻读的推模型,一旦大 V 的内容更新,他的收件箱可能在一瞬间涌入大量的写流量。另外,对于几个头部大 V 来说,收到几千万的点赞并不是什么难事,每一个点赞信息都要写入到该用户的收件箱中,这就要求了底层存储需要能支持海量数据。

基于以上情景,MySQL 可能并不是一个合适的持久化方案。此时,我们可以尝试使用 HBase。

MySQL 与 HBase

MySQL 和 HBase 是我们日常应用中常用的两个数据库,分别解决应用的在线事务问题和大数据场景的海量存储问题。

综合对比

MySQL:是常用的数据库,采用行存储模式,底层是 binlog,用来存储业务数据,数据存储量较小。

HBase:列式数据库,底层是 hdfs,可以存储海量的数据,主要用来存储海量的业务数据和日志数据。

从引擎结构看差异

HBase 和 MySQL 的核心差异在于底层的数据结构,HBase 使用 LSM(Log-Structure Merge)树,Innodb 使用 B+树。

LSM 树,即日志结构合并树(Log-Structured Merge-Tree)。 其实它并不属于一个具体的数据结构,它更多是一种数据结构的设计思想。

它的核心思路其实非常简单,就是假定内存足够大,因此不需要每次有数据更新就必须将数据写入到磁盘中,而可以先将最新的数据驻留在内存中,等到积累到最后多之后,再使用归并排序的方式将内存内的数据合并追加到磁盘队尾 (因为所有待排序的树都是有序的,可以通过合并排序的方式快速合并到一起)。

LSM 具有批量特性,存储延迟。当写读比例很大的时候(写比读多),LSM 树相比于 B 树有更好的性能。因为随着 insert 操作,为了维护 B 树结构,节点分裂。 读磁盘的随机读写概率会变大,性能会逐渐减弱。 多次单页随机写,变成一次多页随机写,复用了磁盘寻道时间,极大提升效率。

因此,由引擎结构(B+Tree vs LSM Tree)看到的能力差异:

  1. MySQL:读写均衡、存在空间碎片
  2. HBase:侧重于写、存储紧凑无浪费、Io 放大、数据导入能力强

从架构对比看差异

相比 MySQL,HBase 的架构特点:

  1. 完全分布式(数据分片、故障自恢复)
  2. 底层使用 HDFS(存储计算分离)。

由架构看到的能力差异:

  1. MySQL:运维简单(组件少)、延时低(访问路径短)
  2. HBase:扩展性好、内置容错恢复与数据冗余

总结

本文我们讲述了如何从官方通知和用户通知两个方面切入,设计一个 App 的常见功能——消息中心。但该方案仍然有很多潜在的问题:如果官方通知的来源很多呢?如何解决写扩散带来的成本问题?这些都是值得探索的问题。

事实上,消息中心虽然是一个十分常见的功能,但背后涉及到的东西非常复杂,发布/订阅、推拉模型、读写扩散等问题都会影响到我们的架构设计。

架构设计的过程,就是取舍的过程,而如何取舍,则是一门学问。对于现在纷繁复杂的互联网业务,永远没有最好的架构,只有最适合的架构。

最后,我们抛个问题,朋友圈是推模型还是拉模型?

相关文章
|
传感器 物联网 数据管理
.NETCore/C#开发IOT嵌入式设备的个人见解
.NETCore/C#开发IOT嵌入式设备的个人见解
1722 0
.NETCore/C#开发IOT嵌入式设备的个人见解
|
数据采集 存储 自然语言处理
如何搭建企业级知识图谱系统
企业级知识图谱系统作为一种基于图谱技术的知识管理工具,能够帮助企业更好地整合、管理和利用知识资源,提高决策效率和准确性,为企业的发展提供有力支持。
|
5月前
|
数据采集 存储 人工智能
企业AI知识库的开发流程
企业AI知识库落地需6步:需求与架构选型→数据清洗→RAG流水线搭建→Prompt工程→系统集成与权限管控→盲测调优。成败关键在数据质量与检索优化,而非单纯选大模型。私有化/云方案依数据敏感度而定。(239字)
|
8月前
|
安全 JavaScript API
OpenClaw进阶保姆级指南!阿里云/本地部署+百炼API配置+集成7个高价值Skill 及实战避坑指南
OpenClaw爆火后,不少用户陷入“技能焦虑”——GitHub上1000+Skills让人眼花缭乱,盲目安装后不仅没提升效率,反而因权限风险、功能冲突、稳定性问题陷入困扰。参考文章作者翻遍GitHub后发现,真正实用、安全、稳定的技能仅占少数,多数只是Demo级工具,甚至存在误删文件等安全隐患。
880 10
|
9月前
|
弹性计算 数据可视化 网络安全
阿里云服务器管理控制台在哪?终于找到了,控制台超级好用
阿里云服务器控制台是管理ECS与轻量应用服务器的可视化后台,支持重启、远程连接、重装系统、备份、配置调整等操作。ECS控制台入口:ecs.console.aliyun.com;轻量服务器入口:swasnext.console.aliyun.com。(239字)
2730 3
|
数据可视化 小程序 Java
重磅发现!Gitee上最有价值的开源项目,官方推荐,WePush再不用就落后啦!!!
WePush 是一款基于 Java Swing 的可视化消息推送平台,支持微信、短信、邮件及 HTTP 请求等多渠道消息推送。其特色在于非技术人员也能轻松配置,实现批量发送、变量替换、定时任务与失败重试等功能,适用于中小团队快速搭建高效推送系统。
846 0
|
JavaScript 前端开发 开发者
36.3K star!开发者专属PPT神器,Markdown秒变炫酷幻灯片!
Slidev 是专为开发者打造的现代化幻灯片制作工具,基于 Markdown + Vue 技术栈实现。它让技术分享、产品演示、教学培训等场景的幻灯片制作效率提升300%,支持实时编码演示、数学公式渲染、流程图绘制等开发者刚需功能,可将.md文件一键转换为网页/PDF/PPTX格式。
1568 4
|
存储 缓存 监控
聊聊消息中心的设计与实现逻辑
消息通知的流程设计,在各个业务线中通过消息中心提供的接口方法,将不同场景下的消息内容提交到消息中心,消息中心进行统一维护管理,并根据消息的来源和去向,适配相应的推送逻辑。
1847 0
聊聊消息中心的设计与实现逻辑
|
人工智能 JSON 自然语言处理
Function AI 工作流发布:以 AI 重塑企业流程自动化
本文介绍了基于函数计算 FC 打造的全新 Function AI 工作流服务,该服务结合 AI 技术与流程自动化,实现从传统流程自动化到智能流程自动化的跨越。文章通过内容营销素材生成、内容安全审核和泛企业 VOC 挖掘三个具体场景,展示了 Function AI 工作流的设计、配置及调试过程,并对比了其与传统流程的优势。Function AI 工作流具备可视化、智能性和可扩展性,成为企业智能化转型的重要基础设施,助力企业提升效率、降低成本并增强敏捷响应能力。
1319 28
|
存储 运维 监控
如何在 Spring Boot 中设计和实现业务操作日志功能?
如何在 Spring Boot 中设计和实现业务操作日志功能?
3195 4