IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

简介: 1、前言IM的群聊消息,究竟存1份(即扩散读方式)还是存多份(即扩散写方式)?上一篇文章《IM群聊消息的已读回执功能该怎么实现?》是说,“很容易想到,是存一份”,被网友们骂了,大家争论的很激烈(见下图)。

1、前言

IM的群聊消息,究竟存1份(即扩散读方式)还是存多份(即扩散写方式)?

上一篇文章《IM群聊消息的已读回执功能该怎么实现?》是说,“很容易想到,是存一份”,被网友们骂了,大家争论的很激烈(见下图)。

网友骂的对,任何技术方案,都不是天才般灵感乍现想到的,一定是一个演进迭代,逐步优化的过程。今天就聊一聊,IM群聊消息,为啥只需要存一份。

不过,从公开的技术资料来看,微信的群聊消息应该使用的是存多份(即扩散写方式),详细的方案可以在微信团队分享的这篇文章里找到答案:《微信后台团队:微信后台异步消息队列的优化升级实践分享》。

学习交流:

- 即时通讯开发交流3群:185926912[推荐]

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

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

2、本文作者

沈剑:58技术委员会主席,58高级架构师,58到家技术总监。C2C技术部负责人,58技术学院优秀讲师。

沈剑的另外几篇有关IM的文章也值得你去阅读:

理论联系实际:一套典型的IM通信协议设计详解

IM群聊消息的已读回执功能该怎么实现?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

3、IM开发干货系列文章

本文是系列文章中的第15篇,总目录如下:

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

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登陆和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登陆接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?》(本文)

另外,如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

4、更多关于IM群聊的文章

IM系统中的群聊功能,是个很大话题,下面几篇在关群聊的文章您也可以读一读:

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

微信后台团队:微信后台异步消息队列的优化升级实践分享

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

关于IM即时通讯群聊消息的乱序问题讨论

IM群聊消息的已读回执功能该怎么实现?

>> 更多同类文章 ……

另外,《一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》一文中也包含了群聊的完整设计,如果您设计IM不知从何下手,可以详细地参考此文。

5、最基本的方案:“在线的群友不存储消息,离线的群友才存储”

群信息,用户信息,群成员关系都是基础数据:

group_info(gid, group_info);

user_info(uid, user_info);

group_members(gid, uid);

假设一个群(gid)里有4个成员,其中三个在线(A, uid1, uid2),一个不在线(uid3)。

A发送了一条消息,很容易想到,对于不同的群友消息存多份,每个群友一个队列来存储。但由于在线的用户会实时的收到消息,所以暂定只为离线的用户存储。

用户收到的群消息,也是基础数据:

user_msgs(uid,msgid,gid,sender_uid,time,content);

很容易想到,整个群消息的发送流程如上图1-4:

1)发送消息;

2)查询状态;

3)不在线的存储离线;

4)在线的实时推送。

“在线的群友不存储,离线的群友才存储”会带来的问题是,如果第四步发生异常,群友会丢失消息。

6、优化的方案:“不管群员是否在线,都要先存储消息”

消息的可达性是聊天系统中最重要的要素(没有之一),故这个方案是不行的,需要优化为“不管是否在线,都要先存储”。

发送群消息的流程优化为,如上图1-4:

1)发送消息;

2)所有人都存一份;

3)查询状态;

4)在线的实时推送。

先将消息落地,能够保证消息可达性,那何时才能删除已经落地的群消息呢?我们继续往下看。

对于在线的群友:收到群消息后,给个ack确认才能删除。

画外音:逻辑删除,还是物理删除,根据业务是否有消息漫游决定。

对于离线的群友:在下次登陆后,拉取完离线消息再给ack确认才能删除。

总之:为了保证消息的可达性,不管是在线消息还是离线消息,必须接收方给ack确认,才能删除消息。

7、“不管群员是否在线,都冗余一份群消息”带来的问题

“不管是否在线,都冗余一份群消息”带来的问题是:同一条消息存储了很多次,对磁盘和带宽造成了很大的浪费。

很容易想到的优化是:群消息实体存储一份,用户只冗余消息ID。

故基础数据可以由:

user_msgs(uid,msgid,gid,sender_uid,time,content);

优化为:

group_msgs(msgid,gid,sender_uid,time,content);

user_msgs(uid, msgid, gid);

这个优化,对于消息投递,以及消息删除的核心流程没有影响,几个实践为:

在线用户投递消息实体,ack消息ID;

离线用户先拉取消息ID,再拉取消息实体,再ack消息ID。

如此这般,假如在某个群友A期间,群里陆续发送了N条消息,则user_msgs(uid, msgid, gid)里,会有 uidA -> mid1,mid2, mid3, … midN 等N条离线记录,拉取离线消息时,可以把这N条消息一次性拉取出来,然后再删除:

delete from user_msgs  where msgid in($mid1,$mid2…, $midN) and gid=$gid

8、终级方案:利用群消息的“偏序”特性优雅地实现“只存1份”

然而,群消息具备“偏序”特性,上面的一次性删除完全可以优化为:

delete from user_msgs 

where msgid >= $mid1 and gid=$gid

这就意味着,每个用户只需要记录“最近一次收到的消息ID”,而不用记录“所有未收到的消息ID集合”,每当收在线消息ack,以及拉离线消息ack时,只需要更新这个“最近一次收到的消息ID”即可。

于是乎,基础数据可以由:

group_members(gid, uid);

group_msgs(msgid,gid,sender_uid,time,content);

user_msgs(uid, msgid, gid);

优化为:

group_members(gid, uid, last_ack_msgid);

group_msgs(msgid,gid,sender_uid,time,content);

user_msgs(uid, msgid, gid); // 不再需要

即:群消息只存储一份,群友无需冗余任何消息实体,或者消息ID了。

对于在线的群友:收到群消息后,修改这个last_ack_msgid。

对于离线的群友:拉取群消息后,也修改这个last_ack_msgid。

画外音:这里的讨论,仅限于接收方收到了哪些消息,和发送方的已读回执没有关系。(这里指的是作者的上篇文章《IM群聊消息的已读回执功能该怎么实现?》)

9、本文小结

任何架构方案都不是灵光一现,而是逐步迭代优化产生的:

方案1:群聊消息存多份,只存在线,消息容易丢;

方案2:群聊消息存多份,所有群友都存储,消息冗余多;

方案3:群聊消息存多份,只存ID,未利用偏序;

终极方案:群聊消息存一份,只存last_ack_msgid。

架构不(只)是设计出来的,更是演进出来的。

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

目录
相关文章
|
3天前
|
缓存 架构师
即时通讯技术文集(第35期):IM群聊技术合集(Part2) [共12篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第35 期。
40 1
|
3天前
|
消息中间件 存储 Rust
即时通讯技术文集(第34期):IM群聊技术合集(Part1) [共15篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第34 期。
30 2
|
存储 Java Go
基于Netty,从零开发IM(三):编码实践篇(群聊功能)
接上两篇《IM系统设计篇》、《编码实践篇(单聊功能)》,本篇主要讲解的是通过实战编码实现IM的群聊功能,内容涉及群聊技术实现原理、编码实践等知识。
185 0
基于Netty,从零开发IM(三):编码实践篇(群聊功能)
|
3天前
|
自然语言处理 监控 数据可视化
海拍客与瓴羊达成合作,通过智能客服系统提升员工内部服务体验
海拍客与瓴羊达成合作,通过智能客服系统提升员工内部服务体验
|
3天前
|
自然语言处理 监控 机器人
中国联通济南分公司与瓴羊达成合作,以智能客服系统提升员工内部服务体验
中国联通济南分公司与瓴羊达成合作,以智能客服系统提升员工内部服务体验
|
3天前
|
存储 数据挖掘 API
解码客服工单系统:选型指南让您信手拈来
在选择客服工单系统时,企业应明确需求,考虑功能(如工单管理、知识库集成、自动化流程)、易用性、技术支持、可扩展性、安全性和合规性。ZohoDesk提供定制服务,满足企业效率提升和成本降低的需求。进行成本效益分析以确保投资回报。
27 6
|
3天前
|
监控 安全 机器人
电话客服热线系统的详细搭建方案(十大关键要素)
构建高效电话客服系统涉及需求分析、话务量估算、系统规划与设计、多渠道集成、智能化升级和安全措施。需求分析包括客户调查、数据分析、竞争分析和焦点小组讨论,以确定服务模型和规模。系统设计需选择合适的服务模型、技术工具,并设计呼叫流程。多渠道接入与在线客服可提升客户体验,智能化技术如智能语音和文字机器人则提高效率。技术实施涉及硬件和软件选择、系统集成、测试与调整。安全方面,要设计安全策略,实施安全技术,并持续监控。人员培训与管理确保团队能力,运营和优化则关注日常管理、系统优化和后期运维。部署方式包括云端和本地化,租用和自建,各有优劣。电话客服系统对提升客户满意度和企业形象至关重要。
|
3天前
|
存储 数据库
工单系统的作用与优势!为什么企业需要它?
**工单系统是管理任务和请求的软件,如ZohoDesk,能提升生产力、提供透明度、增强客户满意度、优化资源分配和促进协作。ZohoDesk工单系统特点包括直观界面、高度可定制、多渠道支持、强大集成能力和报告功能,适合不同规模的组织。**
57 1
|
3天前
|
运维 安全 数据安全/隐私保护
工单系统大揭秘!选择工单系统需注意的关键因素!
这篇内容介绍了工单系统的种类和选择指南。主要类型包括IT工单系统、客户服务工单管理系统、设备维护工单管理系统和全渠道工单系统。选择合适的工单系统需考虑功能需求、企业预算、易用性、系统稳定性、售后服务和技术安全。推荐了Zoho Desk作为好用的工单系统选项,它提供专业服务和免费试用。
34 1

热门文章

最新文章