参考

需求缘起

当发送方用户A发送消息给接收方用户B时,如果用户B在线,之前的文章《微信为啥不丢“在线消息”?》聊过,可以通过应用层的确认,发送方的超时重传,接收方的去重保证业务层面消息的不丢不重。

那如果接收方用户B不在线,系统是如何保证消息的可达性的呢?这是本文要讨论的问题。

问题:接收方不在线时,消息发送的流程是怎么样的?


回答:如上图所述,

(1)用户A发送消息给用户B

(2)服务器查看用户B的状态为offline

(3)服务器将消息存储到DB中

(4)服务器返回用户A发送成功(对于发送方而言,消息落地DB就认为发送成功)

问题:离线消息表的设计,拉取离线的过程?

receiver_uid, msg_id, time, sender_uid,msg_type, msg_content …

访问模式:接收方B要拉取发送方A给ta发送的离线消息,只需在receiver_uid(B), sender_uid(A)上查询,然后把离线消息删除,再把消息返回B即可。


整体流程如上图所述,

(1)用户B拉取用户A发送给ta的离线消息

(2)服务器从DB中拉取离线消息

(3)服务器从DB中把离线消息删除

(4)服务器返回给用户B想要的离线消息

问题:上述流程存在的问题?

回答:如果用户B有很多好友,登陆时客户端需要对所有好友进行离线消息拉取,客户端与服务器交互次数较多

客户端伪代码:

for(all uid in B’s friend-list){      // 登陆时所有好友都要拉取

get_offline_msg(B,uid);   // 与服务器交互

}

优化方案一:先拉取各个好友的离线消息数量,真正用户B进去看离线消息时,才往服务器发送拉取请求(手机端为了节省流量,经常会使用这个按需拉取的优化)


优化方案二:一次性拉取所有好友发送给用户B的离线消息,到客户端本地再根据sender_uid进行计算,这样的话,离校消息表的访问模式就变为->只需要按照receiver_uid来查询了。登录时与服务器的交互次数降低为了1次。

问题:用户B一次性拉取所有好友发给ta的离线消息,消息量很大时,一个请求包很大,速度慢,容易卡顿怎么办?


回答:分页拉取,根据业务需求,先拉取最新(或者最旧)的一页消息,再按需一页页拉取。

问题:如何保证可达性,上述步骤第三步执行完毕之后,第四个步骤离线消息返回给客户端过程中,服务器挂点,路由器丢消息,或者客户端crash了,那离线消息岂不是丢了么(数据库已删除,用户还没收到)?

回答:嗯,如果按照上述的1,2,3,4步流程,的确是的,那如何保证离线消息的可达性?


如同在线消息的应用层ACK机制一样,离线消息拉时,不能够直接删除数据库中的离线消息,而必须等应用层的离线消息ACK(说明用户B真的收到离线消息了),才能删除数据库中的离线消息。

问题:如果用户B拉取了一页离线消息,却在ACK之前crash了,下次登录时会拉取到重复的离线消息么?

回答:拉取了离线消息却没有ACK,服务器不会删除之前的离线消息,故下次登录时系统层面还会拉取到。但在业务层面,可以根据msg_id去重。SMC理论:系统层面无法做到消息不丢不重,业务层面可以做到,对用户无感知。


问题:假设有N页离线消息,现在每个离线消息需要一个ACK,那么岂不是客户端与服务器的交互次数又加倍了?有没有优化空间?


回答:不用每一页消息都ACK,在拉取第二页消息时相当于第一页消息的ACK,此时服务器再删除第一页的离线消息即可,最后一页消息再ACK一次。这样的效果是,不管拉取多少页离线消息,只会多一个ACK请求,与服务器多一次交互。

总结

“离线消息”的可达性可能比大家想象的要复杂,常见的优化有:

(1)对于同一个用户B,一次性拉取所有用户发给ta的离线消息,再在客户端本地进行发送方分析,相比按照发送方一个个进行消息拉取,能大大减少服务器交互次数

(2)分页拉取,先拉取计数再按需拉取,是无线端的常见优化

(3)应用层的ACK,应用层的去重,才能保证离线消息的不丢不重

(4)下一页的拉取,同时作为上一页的ACK,能够极大减少与服务器的交互次数

微信为啥不丢“离线消息”?相关推荐

  1. 微信多点登录与QQ消息漫游架构随想

    [需求缘起] 之前的一些文章简单介绍了 <"单人消息"><"离线消息"><"群消息"><" ...

  2. 微信为什么不丢消息?

    上一章和大家分享了<http如何像tcp一样实时的收消息?>, 本章来聊一聊即时通讯(Instant Messaging,后简称im)消息的可靠投递. 一.报文类型 im的客户端与服务器通 ...

  3. 微信接收离线消息状态的设置方法(图文教程)

    为什么80%的码农都做不了架构师?>>>    摘自:穆童博客 http://mtoou.info 相信大家在上QQ的时候应该发现了很多人在使用腾讯的微信了,而且还常常发现使用了微信 ...

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

    1.前言 本文的上篇<IM消息送达保证机制实现(一):保证在线实时消息的可靠投递>中,我们讨论了在线实时消息的投递可以通过应用层的确认.发送方的超时重传.接收方的去重等手段来保证业务层面消 ...

  5. IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

    1.引言 好久没写技术文章了,今天这篇不是原理性文章,而是为大家分享一下由笔者主导开发实施的IM即时通讯聊天系统,针对大量离线消息(包括消息漫游)导致的用户体验问题的升级改造全过程. 文章中,我将从如 ...

  6. IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

    1.点评 IM聊天消息的可靠投递,是每个线上产品都要考虑的IM热点技术问题. IM聊天消息能保证可靠送达,对于用户来说,就好比把钱存在银行不怕被偷一样,是信任的问题.试想,如果用户能明显感知到聊天消息 ...

  7. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

    1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...

  8. im即时通讯开发:离线消息、历史消息的实践

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

  9. im即时通讯开发:IM系统中离线消息、历史消息实践

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

最新文章

  1. winrunner事务概念的代码应用(毫秒级)
  2. java和python哪个好就业2020-java和python哪个的前途更好?
  3. Python 学习笔记(1)Hello Python
  4. commonjs是什么_JavaScript模块化标准CommonJS/AMD/CMD/UMD/ES6Module的区别
  5. c++ 航空管理系统_浅谈航站楼能源管理系统的设计与应用
  6. 使用Frigga实现WEB方式对服务的监控
  7. R语言数据分析 | 谱系图与聚类分析
  8. CorelDRAW入门教程-用CDR制作漂亮小雨伞
  9. vue填坑之全局引入less,scss,styl文件
  10. 无线网为何显示无法上网络连接服务器,wlan显示已连接不可上网怎么办_wlan显示已连接但无法访问互联网怎么解决...
  11. UVALive 4670 Dominating Patterns(AC自动机)
  12. 博客总纲 博客目录V1
  13. android 筛选电影,Movie - 该看什么电影呢?这几个小程序或许能给你一个选择 - Android 应用 - 【最美应用】...
  14. Proxmox VE
  15. 安装宝塔远程工具流程
  16. python关于FIFA球员的数据分析
  17. NOI的1.8.20反反复复
  18. 计算机第一课 纪律 教案,七年级下信息技术第一单元第一课教案
  19. 迅雷下载原理的源代码(linux c)
  20. Guitar Pro8吉他谱中文正式版

热门文章

  1. 短视频一键去除水印HTML源码
  2. MVC Html.DropDownList 和DropDownListFor 的常用方法
  3. 如何获取微信红包照片的原始清晰图片
  4. 私人订制版微信红包封面(赠送红包封面)
  5. 高通进入不同模式的命令
  6. 流放之路进入服务器时显示,《流放之路》游戏快捷键和界面提示
  7. win11系统之win11亮点
  8. 程序员之路 学习经验总结 副本2
  9. Android 访问FTP 服务器,实现文件的下载
  10. 新浪当初是怎样得到weibo.com域名的