当前位置:网站首页>百万消息量IM系统技术要点分享
百万消息量IM系统技术要点分享
2022-06-23 21:56:00 【wecloud1314】
我们仔细观察就能发现,生活中的任何类型互联网服务都有 IM 系统的存在。
比如:
1)基础性服务类-腾讯新闻(评论消息);
2)商务应用类-钉钉(审批工作流通知);
3)交流娱乐类-QQ/微信(私聊群聊 &讨论组 &朋友圈);
4)互联网自媒体-抖音快手(点赞打赏通知)。

在这些林林总总的互联网生态产品里,即时消息系统作为底层能力,在确保业务正常与用户体验优化上,始终扮演了至关重要的角色。
所以,现如今的互联网产品中,即时通讯技术已经不仅限于传统IM聊天工具本身,它早已通过有形或无形的方式嵌入到了各种形式的互联网应用当中。IM技术(或者说即时通讯技术)对于很多开发者来说,确实是必不好可少的领域知识,不可或缺。
典型的IM系统通常需要满足四点能力:高可靠性、高可用性、实时性和有序性。
以我的这个项目来说,架构设设计要点主要是:
1)微服务:拆分为用户微服务 &消息连接服务 &消息业务服务;
2)存储架构:兼容性能与资源开销,选择 reids&mysql;
3)高可用:可以支撑起高并发场景,选择 Spring 提供的 websocket;
4)支持多端消息同步:app 端、web 端、微信公众号、小程序消息;
5)支持在线与离线消息场景。
理解读扩散和写扩散
我们举个例子说明什么是读扩散,什么是写扩散:
一个群聊“相亲相爱一家人”,成员:爸爸、妈妈、哥哥、姐姐和我(共 5 人)。
因为你最近交到女朋友了,所以发了一条消息“我脱单了”到群里面,那么自然希望爸爸妈妈哥哥姐姐四个亲人都能收到了。
正常逻辑下,群聊消息发送的流程应该是这样:
1)遍历群聊的成员并发送消息;
2)查询每个成员的在线状态;
3)成员不在线的存储离线;
4)成员在线的实时推送。
问题在于:如果第4步发生异常,群友会丢失消息,那么会导致有家人不知道“你脱单了”,造成催婚的严重后果。
所以优化的方案是:不管群员是否在线,都要先存储消息。
按照上面的思路,优化后的群消息流程如下:
1)遍历群聊的成员并发送消息;
2)群聊所有人都存一份;
3)查询每个成员的在线状态;
4)在线的实时推送。
以上优化后的方案,便是所谓的“写扩散”了。
问题在于:每个人都存一份相同的“你脱单了”的消息,对磁盘和带宽造成了很大的浪费(这就是写扩散的最大弊端)。
所以优化的方案是:群消息实体存储一份,用户只存消息 ID 索引。
于是再次优化后的发送群消息流程如下:
1)遍历群聊的成员并发送消息;
2)先存一份消息实体;
3)然后群聊所有人都存一份消息实体的 ID 引用;
4)查询每个成员的在线状态;
5)在线的实时推送。
二次优化后的方案,便是所谓的“读扩散”了。
小结一下:
1)读扩散:读取操作很重,写入操作很轻,资源消耗相对小一些;
2)写扩散:读取操作很轻,写入操作很重,资源消耗相对大一些。
消息实体模型:
常见的消息业务,可以抽象为几个实体模型概念:用户/用户关系/用户设备/用户连接状态/消息/消息队列。
实体模型概念解释:
用户实体:
1)用户->用户终端设备:每个用户能够多端登录并收发消息;
2)用户->消息:考虑到读扩散,每个用户与消息的关系都是 1:n;
3)用户->消息队列:考虑到读扩散,每个用户都会维护自己的一份“消息列表”(1:1),如果考虑到扩容,甚至可以开辟一份消息溢出列表接收超出“消息列表”容量的消息数据(此时是 1:n);
4)用户->用户连接状态:考虑到用户能够多端登录,那么 app/web 都会有对应的在线状态信息(1:n);
5)用户->联系人关系:考虑到用户最终以某种业务联系到一起,组成多份联系人关系,最终形成私聊或者群聊(1:n);
联系人关系(主要由业务决定用户与用户之间的关系),比如说:
1)某个家庭下有多少人,这个家庭群聊就有多少人;
2)在 ToB 场景,在钉钉企业版里,我们往往有企业群聊这个存在。
消息实体:
消息->消息队列:考虑到读扩散,消息最终归属于一个或多个消息队列里,因此群聊场景它会分布在不同的消息队列里。
消息队列实体:
消息队列:确切说是消息引用队列,它里面的索引元素最终指向具体的消息实体对象。
用户连接状态:
1)对于 app 端:网络原因导致断线,或者用户手动 kill 掉应用进程,都属于离线;
2)对于 web 端:网络原因导致浏览器断网,或者用户手动关闭标签页,都属于离线;
3)对于公众号:无法分别离线在线;
4)对于小程序:无法分别离线在线。
用户终端设备:
客户端一般是 Android&IOS,web 端一般是浏览器,还有其他灵活的 WebView(公众号/小程序)。即时通讯开发

消息的存储方案
对于消息存储方案,本质上只有三种方案:要么放在内存、要么放在磁盘、要么两者结合存储(据说大公司为了优化性能,活跃的消息数据都是放在内存里面的,毕竟有钱~)。
下面分别解析主要方案的优点与弊端:
1)方案一:考虑性能,数据全部放到 redis 进行存储;
2)方案二:考虑资源,数据用 redis + mysql 进行存储。
对于方案一:redis
前提:用户 & 联系人关系,由于是业务数据,因此统一默认使用关系型数据库存储。
解释如下:
1)用户发消息;
2)redis 创建一条实体数据 &一个实体数据计时器;
3)redis 在 B 用户的用户队列 添加实体数据引用;
4)B 用户拉取消息(后续 5.2 会提及拉模式)。
实现方案:
1)用户队列,zset(score 确保有序性);
2)消息实体列表,hash(msg_id 确保唯一性);
3)消息实体计数器,hash(支持群聊消息的引用次数,倒计时到零时则删除实体列表的对应消息,以节省资源)。
优点是:内存操作,响应性能好
弊端是:
1)内存消耗巨大,eg:除非大厂,小公司的服务器的宝贵内存资源是耗不起业务的,随着业务增长,不想拓展资源,就需要手动清理数据了;
2)受 redis 容灾性策略影响较大,如果 redis 宕机,直接导致数据丢失(可以使用 redis 的集群部署/哨兵机制/主从复制等手段解决)。
方案二:redis+mysql
前提:用户 & 联系人关系,由于是业务数据,因此统一默认使用关系型数据库存储。
释如下:
1)用户发消息;
2)mysql 创建一条实体数据;
3)redis 在 B 用户的用户队列 添加实体数据引用;
4)B 用户拉取消息(下文会提及拉模式)。
实现方案:
1)用户队列,zset(score 确保有序性);
2)消息实体列表,转移到 mysql(表主键 id 确保唯一性);
3)消息实体计数器,hash(删除这个概念,因为磁盘可用总资源远远高于内存总资源,哪怕一直存放 mysql 数据库,在业务量百万级别时也不会有大问题,如果是巨大体量业务就需要考虑分表分库处理检索数据的性能了)。
优点是:
1)抽离了数据量最大的消息实体,大大节省了内存资源;
2)磁盘资源易于拓展 ,便宜实用。
弊端是:磁盘读取操作,响应性能较差(从产品设计的角度出发,你维护的这套 IM 系统究竟是强 IM 还是弱 IM)。
边栏推荐
- Start learning simple JS
- Mysql中的触发器定义及语法介绍
- SQL Server Common SQL
- sql server常用sql
- How to use fortress remote server two types of Fortress
- 【技术干货】蚂蚁办公零信任的技术建设路线与特点
- Section 30 high availability (HA) configuration case of Tianrongxin topgate firewall
- Beauty of script │ VBS introduction interactive practice
- VNC multi gear resolution adjustment, 2008R2 setting 1280 × 1024 resolution
- Dlib detects 68 facial features, and uses sklearn to train a facial smile recognition model based on SVM
猜你喜欢

Ant won the finqa competition champion and made a breakthrough in AI technology of long text numerical reasoning

Opengauss Developer Day 2022 was officially launched to build an open source database root community with developers
How PostgreSQL creates partition tables

Pourquoi une seule valeur apparaît - elle sur votre carte de données?

Application practice | Apache Doris integrates iceberg + Flink CDC to build a real-time federated query and analysis architecture integrating lake and warehouse
![[technical dry goods] the technical construction route and characteristics of zero trust in ant Office](/img/d1/ce999b9f72bbb8f692c4298b4042aa.png)
[technical dry goods] the technical construction route and characteristics of zero trust in ant Office

Section 30 high availability (HA) configuration case of Tianrongxin topgate firewall

SAVE: 软件分析验证和测试平台

The 12 SQL optimization schemes summarized by professional "brick moving" old drivers are very practical!
Docker中部署Redis集群与部署微服务项目的详细过程
随机推荐
蚂蚁集团自研TEE技术通过国家级金融科技产品认证
December 14, 2021: rebuild the queue according to height. Suppose there's a bunch of people out of order
Slsa: accelerator for successful SBOM
Change sql- Tencent cloud database tdsql elite challenge - essence Q & A
How to set the search bar of website construction and what should be paid attention to when designing the search box
Understand the data consistency between MySQL and redis
Operation and maintenance failure experience sharing
What should I do if the RDP fortress server connection times out? Why should enterprises use fortress machines?
How to create a virtual server through a fortress machine? What are the functions of the fortress machine?
蚂蚁获FinQA竞赛冠军,在长文本数值推理AI技术上取得突破
How to access the server through the fortress machine? What if the fortress computer can't jump to the server?
C language picture transcoding for performance testing
Analysis and application of ThreadLocal source code
Detailed process of deploying redis cluster and micro service project in docker
Performance test - LoadRunner obtains the return value and user-defined parameters (parameter operation)
Source code analysis of jmeter5.1 core class testcompiler
First talk about the necessary skills of Architecture
[tcapulusdb knowledge base] reading data example (TDR table)
The 12 SQL optimization schemes summarized by professional "brick moving" old drivers are very practical!
Low code helps live e-commerce bring goods into the manufacturing industry, impacting the traditional supply chain model of the factory