Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >IM消息机制(一):保证在线实时消息的可靠投递

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

作者头像
子晋
发布于 2022-01-18 13:48:06
发布于 2022-01-18 13:48:06
2.5K0
举报
文章被收录于专栏:子晋城子晋城

互联网发展至今,IM(即时通讯聊天应用)一直是互联网上最为成功也是最为平常的应用类型。尤其现今的移动互联网时代,因即时通讯技术的发展和普及,IM这种即时通讯应用已乎达成了各即时通讯应用运营者梦寐已求的所谓“全时在线”,而这种“全时在线”及其应用体验的背后,回归到技术本质就是各种行为消息(或者说信息)的实时性、必达性。

本文将要讨论的是即时IM应用中极其重要但也不被用户感知的消息送达保证机制(即QoS机制),文中将给出目前主流的参考实现思路。

一、概述

消息的可靠性,即消息的不丢失和不重复,是IM系统中的一个难点。当初QQ在技术上(当时叫OICQ)因为以下两点原因才打败了ICQ:

  • QQ的消息投递可靠(消息不丢失,不重复)
  • QQ的垃圾消息少(它antispam做得好,这也是一个难点,但不是本文重点讨论的内容)

二、报文类型

IM的客户端与服务器通过发送报文(也就是请求包)来完成消息的传递。

报文分为三种:

  1. 请求报文(request,后简称为为R)
  2. 应答报文(acknowledge,后简称为A)
  3. 通知报文(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消息可靠投递的六个报文

我们来参考网络传输协议的实现:UDP是一种不可靠的传输层协议,TCP是一种可靠的传输层协议,TCP是如何做到可靠的?答案是:超时、重传、确认。(实际上IM中,数据通讯层无论用的是UDP还是TCP协议,都同样需要消息送达保证(即QoS)机制,原因在于IM的通信是A端-Server-B端的3方通信,而非传统C/S或B/S这种2方通信)。

要想实现应用层的消息可靠投递,必须加入应用层的确认机制,即:要想让发送方client-A确保接收方client-B收到了消息,必须让接收方client-B给一个消息的确认,这个应用层的确认的流程,与消息的发送流程类似:

  1. client-B向im-server发送一个ack请求包,即ack:R
  2. im-server在成功处理后,回复client-B一个ack响应包,即ack:A
  3. 则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这四个报文都可能丢失: (原因如1.4所述,可能是服务器奔溃、网络抖动、或者客户端奔溃),此时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报文都有可能丢失:

  • msg:N 报文丢失:说明client-B之前压根没有收到“你好”报文,超时与重传机制十分有效
  • 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群消息的可靠投递问题感兴趣的可查阅相关资料。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
webim如何保证消息的可靠投递
《webim如何保证消息的可靠投递》 上一章和大家分享了webim消息的实时性问题 消息的可靠性,即消息的不丢失和不重复,也是im系统中的一个难点。当初qq在技术上(当时叫oicq)因为以下两点原因才打败了icq: 1)qq的消息投递可靠(消息不丢失,不重复) 2)qq的垃圾消息少(它antispam做得好,这也是一个难点,但不是本文重点讨论的内容) 今天,本文将用十分通俗的语言,来讲述webim系统中消息可靠性的问题。 一、报文类型 im的客户端与服务器通过发送报文(也就是网络包)来完成消息的传递,报文分
架构师之路
2018/03/01
1.5K1
webim如何保证消息的可靠投递
微信为什么不丢消息?
上一章和大家分享了《http如何像tcp一样实时的收消息?》, 本章来聊一聊即时通讯(Instant Messaging,后简称im)消息的可靠投递。 一、报文类型 im的客户端与服务器通过发送报文(
架构师之路
2018/03/01
3.7K0
微信为什么不丢消息?
微信:我们绝不丢消息!(第49讲)
有水友问我说,总感觉微信不丢消息,它是怎么做到的? 之前做过几十年IM架构,今天和大家聊聊消息的可靠投递。
架构师之路
2025/04/01
1630
微信:我们绝不丢消息!(第49讲)
IM群聊消息的已读回执功能该怎么实现?
我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知道。
JackJiang
2018/08/29
5.1K0
从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
IM App 是我做过 App 类型里复杂度最高的一类,里面可供深究探讨的技术难点非常之多。这篇文章和大家聊下从移动端客户端的角度所关注的IM消息可靠性和送达机制(因为我个人对移动客户端的经验积累的比较丰富嘛)。
JackJiang
2018/08/29
2.6K0
零基础IM开发入门(三):什么是IM系统的可靠性?
本文编写时引用了“聊聊IM系统的即时性和可靠性”一文的部分内容和图片,感谢原作者。
JackJiang
2020/10/29
9680
基于实践:一套百万消息量小规模IM系统技术要点总结
本文由公众号“后台技术汇”分享,原题“基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统”,原文链接在文末。由于原文存在较多错误和不准确内容,有大量修订和改动。
JackJiang
2021/11/27
2.3K0
基于实践:一套百万消息量小规模IM系统技术要点总结
网络编程懒人入门(四):快速理解TCP和UDP的差异
对于即时通讯开者新手来说,在开始着手编写IM或消息推送系统的代码前,最头疼的问题莫过于到底该选TCP还是UDP作为传输层协议。本文延续《网络编程懒人入门》系列文章的风格,通过快速对比分析 TCP 和 UDP 的区别,来帮助即时通讯初学者快速了解这些基础的知识点,从而在IM、消息推送等网络通信应用场景中能准确地选择合适的传输层协议。
JackJiang
2018/08/23
9070
网络编程懒人入门(四):快速理解TCP和UDP的差异
融云技术分享:全面揭秘亿级IM消息的可靠投递机制
本文由融云技术团队原创分享,原题“IM 消息同步机制全面解析”,为使文章更好理解,对内容进行了重新归纳和细节修订。
JackJiang
2021/07/26
9810
融云技术分享:全面揭秘亿级IM消息的可靠投递机制
本文由融云技术团队原创分享,原题“IM 消息同步机制全面解析”,为使文章更好理解,对内容进行了重新归纳和细节修订。
JackJiang
2021/07/27
8520
转转平台IM系统架构设计与实践(二):详细设计与实现
接上篇《整体架构设计》,笔者将以转转IM架构为起点,介绍IM相关组件以及组件间的关系;以IM登陆和发消息的数据流转为跑道,介绍IM静态数据结构、登陆和发消息时的动态数据变化;以IM常见问题为风景,介绍保证IM实时性、可靠性、一致性的一般方案;以高可用、高并发为终点,介绍保证IM系统稳定及性能的小技巧。
JackJiang
2025/02/13
2320
转转平台IM系统架构设计与实践(二):详细设计与实现
IM消息送达保证机制实现(二):保证离线消息的可靠投递1、前言 2、学习交流3、IM消息送达保证系列文章4、消息接收方不在线时的典型消息发送流程5、典型离线消息表的设计以及拉取离线消息的过程6、上述流
本文的上篇《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》中,我们讨论了在线实时消息的投递可以通过应用层的确认、发送方的超时重传、接收方的去重等手段来保证业务层面消息的不丢不重。
JackJiang
2018/08/23
8820
IM消息送达保证机制实现(二):保证离线消息的可靠投递1、前言
2、学习交流3、IM消息送达保证系列文章4、消息接收方不在线时的典型消息发送流程5、典型离线消息表的设计以及拉取离线消息的过程6、上述流
IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
IM聊天消息能保证可靠送达,对于用户来说,就好比把钱存在银行不怕被偷一样,是信任的问题。试想,如果用户能明显感知到聊天消息无法保证送达,谁还愿意来用你的APP?谁也不希望自已的话就像浮云一样随风飘逝。
JackJiang
2020/07/21
1.8K0
支持百万人超大群聊的Web端IM架构设计与实践
现在IM群聊产品多种多样,有国民级的微信、QQ,企业级的钉钉、飞书,还有许多公司内部的IM工具,这些都是以客户端为主要载体。而且群聊人数通常都是有限制,微信正常群人数上限是500,QQ2000人,收费能达到3000人,这里固然有产品考量,但技术成本、资源成本也是很大的因素。笔者的业务场景上正好需要一个迭代更新快、轻量级(不依赖客户端)、单群百万群成员的纯H5的IM产品。
JackJiang
2025/03/13
2390
支持百万人超大群聊的Web端IM架构设计与实践
【消息队列之rabbitmq】Rabbitmq之消息可靠性投递和ACK机制实战
上篇文章介绍了rabbitmq的基本知识、交换机类型实战《【消息队列之rabbitmq】学习RabbitMQ必备品之一》 这篇文章主要围绕着消息确认机制为中心,展开实战;接触过消息中间件的伙伴都知道,消息会存在以下问题: 1、消息丢失问题和可靠性投递问题; 2、消息如何保证顺序消费; 3、消息如何保证幂等性问题,即重复消费问题等等… 本文主要以Rabbitmq消息中间件解决问题一的实践,其他问题小编会重新写文章总结;
沁溪源
2022/01/13
1.4K0
【消息队列之rabbitmq】Rabbitmq之消息可靠性投递和ACK机制实战
我今天才知道,原来TCP为了保证可靠传输做了这么多
本节内容有点多,不过关于 TCP 的话,除了三四次握手就是可靠传输了,高频重点知识点,大家还是搞清楚比较好。
Java程序猿阿谷
2021/01/14
1.2K0
我今天才知道,原来TCP为了保证可靠传输做了这么多
消息总线能否实现消息必达?
一、缘起 上周讨论了两期环形队列的业务应用: 《高效定时任务的触发》 《延迟消息的快速实现》 两期的均有大量读者提问: 任务、延迟消息都放在内存里,万一重启了怎么办? 能否保证消息必达? 今天就简单聊
架构师之路
2018/03/01
1.7K0
消息总线能否实现消息必达?
IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
上一篇文章《IM群聊消息的已读回执功能该怎么实现?》是说,“很容易想到,是存一份”,被网友们骂了,大家争论的很激烈(见下图)。
JackJiang
2018/08/29
1.7K0
自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
一直想写一篇关于im即时通讯分享的文章,无奈工作太忙,很难抽出时间。今天终于从公司离职了,打算好好休息几天再重新找工作,趁时间空闲,决定静下心来写一篇文章,毕竟从前辈那里学到了很多东西。
JackJiang
2019/07/22
1.2K0
tcp / udp 协议及其实现的soc
一、tcp协议 1.1 基本知识 特点: 可靠,慢,全双工通信 建立连接时:三次握手 断开连接时:四次挥手 在建立起连接之后 发送的每一条信息都有回执 为了保证数据的完整性,还有重传机制 长连接:会一直占用双方的端口 IO(input,output)操作,输入和输出是相对内存来说的 write send - output read recv - input 能够传递的数据长度几乎没有限制 应用场景: 文件的上传下载 发送邮件,网盘,缓存电影等 简述三次握手和四次挥手 三次握手 accept接受
py3study
2020/01/15
7260
推荐阅读
webim如何保证消息的可靠投递
1.5K1
微信为什么不丢消息?
3.7K0
微信:我们绝不丢消息!(第49讲)
1630
IM群聊消息的已读回执功能该怎么实现?
5.1K0
从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
2.6K0
零基础IM开发入门(三):什么是IM系统的可靠性?
9680
基于实践:一套百万消息量小规模IM系统技术要点总结
2.3K0
网络编程懒人入门(四):快速理解TCP和UDP的差异
9070
融云技术分享:全面揭秘亿级IM消息的可靠投递机制
9810
融云技术分享:全面揭秘亿级IM消息的可靠投递机制
8520
转转平台IM系统架构设计与实践(二):详细设计与实现
2320
IM消息送达保证机制实现(二):保证离线消息的可靠投递1、前言 2、学习交流3、IM消息送达保证系列文章4、消息接收方不在线时的典型消息发送流程5、典型离线消息表的设计以及拉取离线消息的过程6、上述流
8820
IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
1.8K0
支持百万人超大群聊的Web端IM架构设计与实践
2390
【消息队列之rabbitmq】Rabbitmq之消息可靠性投递和ACK机制实战
1.4K0
我今天才知道,原来TCP为了保证可靠传输做了这么多
1.2K0
消息总线能否实现消息必达?
1.7K0
IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
1.7K0
自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
1.2K0
tcp / udp 协议及其实现的soc
7260
相关推荐
webim如何保证消息的可靠投递
更多 >
LV.0
斑马网络资深开发工程师
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档