IM开发干货分享:浅谈IM系统中离线消息、历史消息的最佳实践

简介: 本文将基于IM消息系统的技术实践,分享关于离线消息和历史消息的正确理解,以及具体的技术配合和实践,希望能为你的离线消息和历史消息技术设计带来最佳实践灵感。

本文由融云技术团队原创分享,原题“IM 消息数据存储结构设计”,内容有修订。

1、引言

在如今的移动互联网时代,IM类产品已是我们生活中不可或缺的组成部分。像微信、钉钉、QQ等是典型的以 IM 为核心功能的社交产品。另外也有一些应用虽然IM功能不是核心,但IM能力也是其整个应用极其重要的组成部分,比如在线游戏、电商直播等应用。

在IM技术应用场景越来越广泛的前提下,对即时通讯IM技术的学习和掌握就显的越来越有必要。

在IM庞大的技术体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储,而离线消息和历史消息又是这个关键环节中不可回避的技术要点。

本文将基于IM消息系统的技术实践,分享关于离线消息和历史消息的正确理解,以及具体的技术配合和实践,希望能为你的离线消息和历史消息技术设计带来最佳实践灵感。

cover-opti.png

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

2、相关文章

技术相关文章:

  1. 什么是IM系统的可靠性?
  2. 闲鱼IM的在线、离线聊天数据同步机制优化实践
  3. 闲鱼亿级IM消息系统的可靠投递优化实践
  4. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
  5. IM消息送达保证机制实现(二):保证离线消息的可靠投递
  6. 我是如何解决大量离线消息导致客户端卡顿的

融云技术团队分享的其它文章:

  1. 融云安卓端IM产品的网络链路保活技术实践
  2. 全面揭秘亿级IM消息的可靠投递机制
  3. 解密融云IM产品的聊天消息ID生成策略
  4. 万人群聊消息投递方案的思考和实践
  5. 基于WebRTC的实时音视频首帧显示时间优化实践
  6. 融云IM技术分享:万人群聊消息投递方案的思考和实践

3、IM消息投递的一般做法

在通常的IM消息系统中,对于实时消息、离线消息、历史消息大概都是下面这样的技术思路。

对于在线用户:消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。

而对于离线的用户:服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除。

这样实现的缺点就是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。

PS:实际上,这其实也不能算是缺点,因为一些场景下存储历史消息并不是必须的,所谓的消息漫游能力也不是必备的,比如微信。

而在我们设计的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库及历史消息库中进行消息的落地存储,而历史消息的落地也就能支持消息漫游等相关功能了。

4、什么是离线消息和历史消息?

关于离线消息和历史消息,在技术上,我们是这样定义。

1)离线消息:

离线消息就是用户(即接收方)在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。

以我们的系统经验来说,我们的离线消息默认只保存最近七天的消息。

用户(即接收方)在下次登录后会全量获取这些离线消息,然后在客户端根据聊天会话进行离线消息的UI展示(比如显示一个未读消息气泡等)。

PS:用户离线的可能性在技术上其实是由很多种情况组成的,比如对方不在线、对方网络断掉了、对方手机崩溃了、服务器发送时出错了等等,严格来讲——只要无法实时发送成的消息,都算“离线消息”。

2)历史消息:

历史消息存储了用户所有的聊天消息,这些消息包括发出的消息以及接收到的消息。

在客户端获取历史消息时,通常是按照会话进行分页获取的。

以我们的系统经验来说,历史消息的存储时间我们设计默认为半年,当然这个时间可以按实际的产品运营规则来定,没有硬性规定。

5、IM消息的发送及存储流程

以下是我们系统整体的消息发送及存储流程:

1.png

如上图所示:当用户发送聊天消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。

这个过程中:对于在线的接收方,会选择直接推送消息。但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,比如接收方会主动向服务器拉取未收到的消息。但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

消息系统存储离线的过程中,为了不影响整个系统的更为平稳,我们使用了MQ消息队列进行IO解偶,所以聊天消息实际上是异步存入到离线库中的(通过MQ进行慢IO解偶,这其实也是惯常做法)。

在分发完消息后:消息服务会同步一份消息数据到历史消息服务中,历史消息服务同样会对消息进行落地存储。

对于新的客户端设备:会有同步消息的需求(所谓的消息漫游能力),而这也正是历史消息的主要作用。在历史消息库中,客户端是可以拉取任意会话的全量历史消息的。

6、IM离线消息、历史消息在存储逻辑上的区别

6.1 概述

通过上面的图中能清晰的看到:

  • 1)离线消息我们存储介质选用的是 Redis
  • 2)历史消息我们选用的是 HBase

对于为什么选用不同的存储介质,其实我们考虑的是离线消息和历史消息不同的业务场景和读写模式。

下面我们重点介绍一下离线消息和历史消息存储的区别。

6.2 离线消息存储模式——“扩散写”

离线消息的存储模式我们用的是扩散写。

2.png

如上图所示:每个用户都有自己单独的收件箱和发件箱:

  • 1)收件箱存放的是需要向这个接收端同步的所有消息;
  • 2)发件箱里存放的是发送端发出的所有消息。

以单聊为例:聊天中的两人会话中,消息会产生两次写,即发送者的发件箱和接收端的收件箱。

而在群的场景下:写入会被更加的放大(扩散),如果群里有 N 个人,那一条群消息就会被扩散写 N 次。

小结一下:

  • 1)扩散写的优点是:接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力;
  • 2)扩散写的缺点是:写入会被成指数地放大,特别是针对群这种场景。

6.3 历史消息存储模式——“扩散读”

历史消息的存储模式我们用的是扩散读。

因为历史消息中,每个会话都保存了整个会话的全量消息。在扩散读这种模式下,每个会话的消息只保存一次。

对比扩散写模式,扩散读的优点和缺点如下:

  • 1)优点是:写入次数大大降低,特别是针对群消息,只需要存一次即可;
  • 2)缺点是:接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

3.png

6.4 小结

在 IM 这种应用场景下,通常会用到扩散写这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。

一个优化好的IM系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。

当然扩散写这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。

综合来讲:我们需要根据自己的业务场景做相应设计选择,以我们的IM系统为例,就是是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。适合的才是最好的,没有必要死搬硬套理论。

7、IM客户端的拉取消息逻辑

7.1 离线消息拉取逻辑

对于IM客户端而言,离线消息的获取针对的是自己的整个离线消息,包括所有的会话(直白了说,就是上线时拉取此次离线过程中的所有未收取的离线消息)。

离线消息的获取是自上而下的方式(按时间序),我们的经验是一次获取 200 条(PS:如果离线消息过多,会分页多次拉取,拉取1“次”可以理解为拉取1“页”)。

在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳。

通过上节的图我们应该知道,离线消息我们存储的是一个线性结构(指的是按时间顺序),Server 会根据这个时间戳向下查找离线消息。当重装或者新安装 App 时,客户端的“当前客户端缓存的消息的最大时间戳”可以传 0 上来。

Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

7.2 历史消息拉取逻辑

历史消息的获取通常针对的是单一会话。

在拉取过程中,需要向服务端提交两个参数:

  • 1)对方的 ID(如果是单聊的话就是对方的 UserID,如果是群则是群组ID);
  • 2)当前会话的最前面消息的时间戳(即当前会话最老一条消息的时间戳)。

Server据这两个参数,可以定位到这个客户端的此会话,然后一次获取 20 条历史消息。

消息的拉取时序上采用的是自下而上的方式(也就是时间序逆序),即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

上面的拉取逻辑,在IM界面功能上通常对应的是下拉或点击“加载更多”,比如这样:

4.jpg

8、本文小结

本文主要分享了IM中有关离线消息和历史消息的正确,主要包括离线消息和历史消息的区别,以及二者在存储、分发、拉取逻辑方面的最佳践等。如对文中内容有异议,欢迎留言讨论。

9、参考资料

[1] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[2] 一套原创分布式即时通讯(IM)系统理论架构方案

[3] 从零到卓越:京东客服即时通讯系统的技术架构演进历程

[4] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[5] 闲鱼亿级IM消息系统的架构演进之路

[6] 闲鱼亿级IM消息系统的可靠投递优化实践

[7] 闲鱼亿级IM消息系统的及时性优化实践

[8] 基于实践:一套百万消息量小规模IM系统技术要点总结

[9] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[10] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[11] 零基础IM开发入门(一):什么是IM系统?

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

目录
相关文章
|
2月前
|
网络协议 NoSQL API
转转客服IM系统的WebSocket集群架构设计和部署方案
客服IM系统是转转自研的在线客服系统,是用户和转转客服沟通的重要工具,主要包括机器人客服、人工客服、会话分配、技能组管理等功能。在这套系统中,我们使用了很多开源框架和中间件,今天讲一下客服IM系统中WebSocket集群的的实践和应用。
211 0
|
4月前
|
前端开发 JavaScript Java
智能客服系统的技术栈解析-唯一客服系统技术架构优势
“唯一客服系统”采用 Vue.js 2.x + ElementUI 构建前端,实现响应式界面,支持多端适配;后端基于 Golang + Gin + GORM,具备高性能与高并发处理能力。系统支持私有化部署,提供灵活定制、AI 扩展能力,技术栈简洁易维护,兼顾开发者友好与企业级应用需求。
247 1
|
4月前
|
测试技术 Go
客服系统程序入口文件解析-唯一客服系统源码开发
该代码为 Go 语言编写的客服系统命令行程序入口,结构清晰,使用 cmd 包启动业务逻辑,可能基于 cobra 框架实现,具备良好可扩展性与可维护性,适用于服务启动与管理。
226 69
|
3月前
|
数据安全/隐私保护 容器 Go
开源IM即时通讯系统调研
Lumen IM 是一款企业级开源即时通讯工具,前端采用 Vue3 + Naive UI,后端基于 Go 语言,使用 WebSocket 协议。支持 Docker + Nginx 快速部署,适合私有化环境。功能包括文本、图片、文件消息,内置笔记、群聊及消息历史记录。界面美观、功能完善,适用于企业沟通、团队协作及开发者学习。提供前后端源码,便于快速搭建 IM 系统。
开源IM即时通讯系统调研
|
3月前
|
移动开发 网络协议 小程序
鸿蒙NEXT即时通讯/IM系统RinbowTalk v2.4版发布,基于MobileIMSDK框架、ArkTS编写
RainbowTalk是一套基于开源即时通讯讯IM框架 MobileIMSDK 的产品级鸿蒙NEXT端IM系统。纯ArkTS编写、全新开发,没有套壳、也没走捷径,每一行代码都够“纯血”。与姊妹产品RainbowChat和RainbowChat-Web 技术同源,历经考验。
204 1
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
从0搭建AI智能客服教程(AI智能客服系统选型和实战指南)
针对智能客服技术与业务脱节的痛点,合力亿捷通过 NLP、知识图谱及人机协同策略,助企业实现首次解决率超 70%、人力成本降 43%、年省成本超千万。其方案提升制造业问题解决率 40%,投诉转接成功率达 99%,以分场景选型助力超万家企业平衡业务与成本,成行业首选。
|
4月前
|
缓存 移动开发 网络协议
纯血鸿蒙NEXT即时通讯/IM系统:RinbowTalk正式发布,全源码、纯ArkTS编写
RainbowTalk是一套基于MobileIMSDK的产品级鸿蒙NEXT端IM系统,目前已正式发布。纯ArkTS、从零编写,无套壳、没走捷径,每一行代码都够“纯”(详见:《RainbowTalk详细介绍》)。 MobileIMSDK是一整套开源IM即时通讯框架,历经10年,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp、鸿蒙NEXT,服务端基于Netty编写。
319 1
|
4月前
|
移动开发 缓存 前端开发
可二次开发的在线客服系统-前后端混合渲染模式
服务端渲染(SSR)结合API交互,提升首屏加载速度与SEO友好性,适用于混合渲染模式的Web应用。
96 0
|
4月前
|
Kubernetes Go 数据库
客服系统命令行程序-Cobra 命令行应用入口
唯一客服系统是基于 Go 语言与 Cobra 框架构建的命令行工具,用于管理在线客服系统。支持启动、安装和停止服务,具备清晰的命令结构和良好的扩展性,便于维护与功能拓展。
141 0

热门文章

最新文章