`

IM如何保证消息可靠性

    博客分类:
  • IM
IM 
阅读更多
转自:https://blog.csdn.net/u014105540/article/details/80539507
今天手机的微信收到的消息总是会延迟,于是了解了一下。
消息的可靠性,即消息的不丢失和不重复,是im系统中的一个难点。当初qq在技术上(当时叫oicq)因为以下两点原因才打败了icq:
1)qq的消息投递可靠(消息不丢失,不重复)
2)qq的垃圾消息少(它antispam做得好,这也是一个难点,但不是本文重点讨论的内容)
今天,本文将用十分通俗的语言,来讲述IM系统中消息可靠性的问题。

一、报文类型
im的客户端与服务器通过发送报文(也就是请求包)来完成消息的传递,报文分为三种,请求报文(request,后简称为为R),应答报文(acknowledge,后简称为A),通知报文(notify,后简称为N),这三种报文的解释如下:
这里写图片描述
R:客户端主动发送给服务器的报文
A:服务器被动应答客户端的报文,一个A一定对应一个R
N:服务器主动发送给客户端的报文

二、普通消息投递流程
用户A给用户B发送一个“你好”,很容易想到,流程如下:
这里写图片描述
1)client-A向im-server发送一个消息请求包,即msg:R
2)im-server在成功处理后,回复client-A一个消息响应包,即msg:A
3)如果此时client-B在线,则im-server主动向client-B发送一个消息通知包,即msg:N(当然,如果client-B不在线,则消息会存储离线)

三、上述消息投递流程出现的问题
从流程图中容易看到,发送方client-A收到msg:A后,只能说明im-server成功接收到了消息,并不能说明client-B接收到了消息。在若干场景下,可能出现msg:N包丢失,且发送方client-A完全不知道,例如:
1)服务器崩溃,msg:N包未发出
2)网络抖动,msg:N包被网络设备丢弃
3)client-B崩溃,msg:N包未接收
结论是悲观的:接收方client-B是否有收到msg:N,发送方client-A完全不可控,那怎么办呢?

四、应用层确认+im消息可靠投递的六个报文
upd是一种不可靠的传输层协议,tcp是一种可靠的传输层协议,tcp是如何做到可靠的?答案是:超时、重传、确认。
要想实现应用层的消息可靠投递,必须加入应用层的确认机制,即:要想让发送方client-A确保接收方client-B收到了消息,必须让接收方client-B给一个消息的确认,这个应用层的确认的流程,与消息的发送流程类似:
这里写图片描述
4)client-B向im-server发送一个ack请求包,即ack:R
5)im-server在成功处理后,回复client-B一个ack响应包,即ack:A
6)则im-server主动向client-A发送一个ack通知包,即ack:N
至此,发送“你好”的client-A,在收到了ack:N报文后,才能确认client-B真正接收到了“你好”。
会发现,一条消息的发送,分别包含(上)(下)两个半场,即msg的R/A/N三个报文,ack的R/A/N三个报文,一个应用层即时通讯消息的可靠投递,共涉及6个报文,这就是im系统中消息投递的最核心技术(如果某个im系统不包含这6个报文,不要谈什么消息的可靠性)。

五、可靠消息投递存在什么问题
期望六个报文完成消息的可靠投递,但实际情况下:
1)msg:R,msg:A报文可能丢失,此时直接提示“发送失败”即可,问题不大
2)msg:N,ack:R,ack:A,ack:N这四个报文都可能丢失(原因如第二章所述,可能是服务器奔溃、网络抖动、或者客户端奔溃),此时client-A都收不到期待的ack:N报文,即client-A不能确认client-B是否收到“你好”,那怎么办呢?

六、消息的超时与重传
client-A发出了msg:R,收到了msg:A之后,在一个期待的时间内,如果没有收到ack:N,client-A会尝试将msg:R重发。可能client-A同时发出了很多消息,故client-A需要在本地维护一个等待ack队列,并配合timer超时机制,来记录哪些消息没有收到ack:N,以定时重发。
这里写图片描述
一旦收到了ack:N,说明client-B收到了“你好”消息,对应的消息将从“等待ack队列”中移除。

七、消息的重传存在什么问题
第五章提到过,msg:N报文,ack:N报文都有可能丢失:
1)msg:N报文丢失,说明client-B之前压根没有收到“你好”报文,超时与重传机制十分有效
2)ack:N报文丢失,说明client-B之前已经收到了“你好”报文(只是client-A不知道而已),超时与重传机制将导致client-B收到重复的消息,那怎么办呢?
启示:
平时使用qq,或许大伙都有类似的体验,弹出一个对话框“因为网络原因,消息发送失败,是否要重发”,此时,有可能是对方没有收到消息(发送方网络不好,msg:N丢失),也可能已经收到了消息(接收方网络不好,反复重传后,ack:N依然丢失),出现这个提示时,大伙不妨和对端确认一下,看是哪种情况。

八、消息的去重
解决方法也很简单,由发送方client-A生成一个消息去重的msgid,保存在“等待ack队列”里,同一条消息使用相同的msgid来重传,供client-B去重,而不影响用户体验。

九、其他
1)上述设计理念,由客户端重传,可以保证服务端无状态性(架构设计基本准则)
2)如果client-B不在线,im-server保存了离线消息后,要伪造ack:N发送给client-A
3)离线消息的拉取,为了保证消息的可靠性,也需要有ack机制,但由于拉取离线消息不存在N报文,故实际情况要简单的多,即先发送offline:R报文拉取消息,收到offline:A后,再发送offlineack:R删除离线消息

十、总结
1)im系统是通过超时、重传、确认、去重的机制来保证消息的可靠投递,不丢不重
2)切记,一个“你好”的发送,包含上半场msg:R/A/N与下半场ack:R/A/N的6个报文

个人消息是一个1对1的ack,群消息就没有这么简单了,群消息存在一个扩散系数,如果大家感兴趣,下一次将和大家讨论im群消息的可靠投递。
分享到:
评论

相关推荐

    理解IM消息可靠性和一致性问题,以及解决方案探讨.docx

    ### 理解IM消息可靠性和一致性问题,以及解决方案探讨 #### 1. 引言 即时通讯(Instant Messaging, IM)系统的核心在于确保消息能够可靠地送达,并且保持消息内容的一致性。若不能满足这两项基本要求,IM软件将...

    马士兵百万级并发IM即时消息系统

    该系统的核心是利用Go语言的高性能特性,结合现代Web开发框架Gin来构建,旨在处理百万级别的并发连接,提供低延迟、高可靠性的消息传递服务。 1. **Go语言的优势** Go语言,又称为Golang,由Google开发,旨在提高...

    C# 编写的IM通讯,稳定性好,含有Demo

    描述中提到的"稳定性好",意味着这个IM系统在设计和实现时考虑了系统的可靠性和健壮性,能够保证在各种网络环境和高并发情况下稳定运行,不会轻易出现崩溃或数据丢失的情况。 关键词"通讯,即时通讯"是这个项目的...

    java 对接腾讯IM 聊天功能接口

    2. **发单聊消息之前回调**:在发送单聊消息前,我们可能需要执行一些预处理操作,例如验证发送者身份、检查消息内容合法性等。回调函数在此时发挥作用,当调用发送消息的接口时,先执行回调函数,确保所有前置条件...

    WebSocket长连接实现聊天IM 接收发送消息,百分百能用

    - **重连机制**:为了确保聊天的可靠性,需要设计重连策略。当连接断开时,可以设置一个延迟后尝试重新连接,但应限制重试次数,避免无限循环。 5. **WebSocket与IM的结合**: - **用户认证**:在建立WebSocket...

    oce im3512 im4512 驱动64位

    带有WHQL标志的驱动意味着它已经通过了微软的严格测试,可以保证在Windows系统下的稳定性和可靠性。这表明,这个OCE驱动程序在64位的Windows 2003、XP和Vista上可以安全、稳定地工作。 安装这个驱动的过程通常包括...

    IM客户端与服务器

    UDP打洞技术使得客户端可以直接通信,提高效率,而可靠性的UDP数据传输则保证了消息的准确无误。 总的来说,这个项目展示了如何在VC7环境下利用UDP协议开发一个基础的IM系统,并通过UDP打洞和可靠性传输技术来克服...

    个人IM程序源代码-IM程序

    3. **消息队列与推送**:IM系统中,消息发送和接收往往通过消息队列来管理,以确保消息的顺序性和一致性。开发者需要理解如何设计和实现高效的消息队列,并且可能会用到消息推送服务,如Apple的APNs或Google的FCM。 ...

    golang实现高性能IM单聊系统,UDP分发

    然而,为了在IM系统中实现类似TCP的可靠性,我们需要在应用层添加一些额外的机制,例如序列号、重传和确认。 在Golang中,`net`包提供了对UDP的原生支持。我们可以使用`net.DialUDP`或`net.ListenUDP`来创建UDP连接...

    陌陌IM高可用架构.pdf

    陌陌在设计通信协议时,其目标是确保通信的高效性(在弱网络环境下快速收发),可靠性(确保消息不丢失),以及扩展性(系统易于横向扩展)。 通信协议的格式通常包含Flag、Length和Data三部分,其中Flag用于标识...

    web IM 用异步实现的IM

    8. **实时消息队列**:如RabbitMQ、Kafka或Redis,用于处理大量并发的消息传递,保证消息的可靠性和顺序性。 9. **安全考虑**:如使用HTTPS保证通信安全,JWT进行身份验证,防止XSS和CSRF攻击。 10. **推送服务**:...

    考拉开源仿微信uniapp前端+JAVA后端IM即时通讯

    2. 消息服务:基于RabbitMQ或Kafka等消息队列,实现异步处理用户的消息发送和接收,提高系统的响应速度和可靠性。 3. 数据存储:使用MySQL或MongoDB等数据库,存储用户信息、聊天记录等数据,同时可能利用Redis等...

    im聊天(app,h5,微信小程序) im.zip

    它需要高效的消息推送机制,例如采用WebSocket协议来实现双向通信,确保消息的即时性和可靠性。 3. **WebSocket协议**:WebSocket是一种在客户端和服务器之间建立持久连接的协议,支持全双工通信。在IM系统中,...

    即时通讯(IM)

    8. **服务质量(QoS)**:为了保证良好的用户体验,IM系统需要关注服务质量,包括消息的可靠传输、低延迟、高并发处理能力等。 在`ym_vcpp-imsoft_hicode`这个压缩包文件中,可能包含了一套基于C++开发的即时通讯...

    im.rar_im

    即时通讯的核心在于实时性和可靠性,它需要处理用户之间的消息传递,包括一对一、一对多甚至多对多的通信模式。常见的IM协议有SMTP(Simple Mail Transfer Protocol)、XMPP(Extensible Messaging and Presence ...

    java IM即时通讯

    6. 安全性:IM系统必须确保通信的隐私,防止中间人攻击,通常采用SSL/TLS协议进行加密。 三、Java IM技术栈 1. Spring Boot:用于快速构建后端服务,提供依赖管理和自动配置功能。 2. WebSocket:提供全双工通信...

    毕业设计 IM 聊天

    - **TCP/IP协议**:IM系统通常基于TCP/IP协议栈,因为它提供可靠的数据传输,确保消息不丢失、不重复。 - **Socket编程**:用于建立客户端与服务器之间的连接,发送和接收数据。在Python中,可以使用socket库来...

    基于Java语言开发IM即时通讯聊天系统源码.zip

    8. **分布式服务**:在大型IM系统中,可能需要使用到分布式服务框架,如Zookeeper进行服务注册与发现,RabbitMQ或Kafka实现消息队列,保证消息的可靠传输。 9. **安全性**:SSL/TLS协议确保通信安全,防止中间人...

    即时通讯IM(2.完整源代码).

    4. **实时同步**:为了保证消息的实时性,IM系统需要实现心跳机制,定期发送心跳包以检测网络状态,并在断线后迅速重连。同时,服务器需要实现消息推送,将新消息实时推送到客户端。 5. **安全与隐私**:IM系统必须...

    模仿腾讯IM Delphi源码

    1. **网络通信**:IM系统的核心是网络通信,通常使用TCP或UDP协议来保证数据的可靠传输。在Delphi中,可以使用TIdTCPClient和TIdTCPServer组件来实现。 2. **协议设计**:IM系统需要定义一套自己的通信协议,包括...

Global site tag (gtag.js) - Google Analytics