专栏首页架构师之路webim如何保证消息的可靠投递

webim如何保证消息的可靠投递

《webim如何保证消息的可靠投递》

上一章和大家分享了webim消息的实时性问题

消息的可靠性,即消息的不丢失和不重复,也是im系统中的一个难点。当初qq在技术上(当时叫oicq)因为以下两点原因才打败了icq: 1)qq的消息投递可靠(消息不丢失,不重复) 2)qq的垃圾消息少(它antispam做得好,这也是一个难点,但不是本文重点讨论的内容) 今天,本文将用十分通俗的语言,来讲述webim系统中消息可靠性的问题。

一、报文类型 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群消息的可靠投递。

本文分享自微信公众号 - 架构师之路(road5858),作者:58沈剑

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2015-04-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 微信为什么不丢消息?

    上一章和大家分享了《http如何像tcp一样实时的收消息?》, 本章来聊一聊即时通讯(Instant Messaging,后简称im)消息的可靠投递。 一、报文...

    架构师之路
  • 58到家通用实时消息平台架构细节(Qcon2016)

    2016Qcon北京,业务核心架构场,《58到家通用实时消息平台架构细节》。 一、解决什么问题 + 难点 解决什么业务问题 (1)端到云的实时上报需求:58速运...

    架构师之路
  • 系统通知,居然有人使用拉取?

    广义系统通知,有1对1的通知,以及一对多的通知,有相对实时的业务通知,以及能够容忍一定延时的系统通知。结合具体的场景来看下,这样的一些系统通知,究竟是推还是拉?

    架构师之路
  • 微信为什么不丢消息?

    上一章和大家分享了《http如何像tcp一样实时的收消息?》, 本章来聊一聊即时通讯(Instant Messaging,后简称im)消息的可靠投递。 一、报文...

    架构师之路
  • IP地址的分配过程

    IP地址的分配一般分为俩种,手动配置和动态获取。服务器主机一般采用手动配置,而客户端主机(比如我们的手机)采用动态获取。原因有以下几个: 1、 客户主机比服务...

    用户7557625
  • 【leetcode刷题】T160-三角形最小路径和

    https://leetcode-cn.com/problems/triangle/

    木又AI帮
  • JavaScript 笔试题(三)

    第三行,首先会对 a.x 进行查找,没有找到就会先赋值 undefined,即:{n: 1, x: undefined}。此时 a 和 b 都指向同一个对象。然...

    多云转晴
  • Java|Spring Cloud Stream 体系及原理介绍

    Spring Cloud Stream 在 Spring Cloud 体系内用于构建高度可扩展的基于事件驱动的微服务,其目的是为了简化消息在 Spring Cl...

    heidsoft
  • SQLite 基础

    第1页:limit 0, 5 第2页:limit 5, 5 第3页:limit 10, 5 … 第n页:limit 5*(n-1), 5

    hrscy
  • [LeetCode] 120. Triangle

    【原题】 Given a triangle, find the minimum path sum from top to bottom. Each step...

    用户1148830

扫码关注云+社区

领取腾讯云代金券