微信为啥不丢“离线消息”?
参考
需求缘起
当发送方用户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,能够极大减少与服务器的交互次数
微信为啥不丢“离线消息”?相关推荐
- 微信多点登录与QQ消息漫游架构随想
[需求缘起] 之前的一些文章简单介绍了 <"单人消息"><"离线消息"><"群消息"><" ...
- 微信为什么不丢消息?
上一章和大家分享了<http如何像tcp一样实时的收消息?>, 本章来聊一聊即时通讯(Instant Messaging,后简称im)消息的可靠投递. 一.报文类型 im的客户端与服务器通 ...
- 微信接收离线消息状态的设置方法(图文教程)
为什么80%的码农都做不了架构师?>>> 摘自:穆童博客 http://mtoou.info 相信大家在上QQ的时候应该发现了很多人在使用腾讯的微信了,而且还常常发现使用了微信 ...
- IM消息送达保证机制实现(二):保证离线消息的可靠投递
1.前言 本文的上篇<IM消息送达保证机制实现(一):保证在线实时消息的可靠投递>中,我们讨论了在线实时消息的投递可以通过应用层的确认.发送方的超时重传.接收方的去重等手段来保证业务层面消 ...
- IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的
1.引言 好久没写技术文章了,今天这篇不是原理性文章,而是为大家分享一下由笔者主导开发实施的IM即时通讯聊天系统,针对大量离线消息(包括消息漫游)导致的用户体验问题的升级改造全过程. 文章中,我将从如 ...
- IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
1.点评 IM聊天消息的可靠投递,是每个线上产品都要考虑的IM热点技术问题. IM聊天消息能保证可靠送达,对于用户来说,就好比把钱存在银行不怕被偷一样,是信任的问题.试想,如果用户能明显感知到聊天消息 ...
- 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)
1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...
- im即时通讯开发:离线消息、历史消息的实践
在如今的移动互联网时代,IM类产品已是我们生活中不可或缺的组成部分.像微信.钉钉.QQ等是典型的以 IM 为核心功能的社交产品.另外也有一些应用虽然IM功能不是核心,但IM能力也是其整个应用极其重要的 ...
- im即时通讯开发:IM系统中离线消息、历史消息实践
在如今的移动互联网时代,IM类产品已是我们生活中不可或缺的组成部分.像微信.钉钉.QQ等是典型的以 IM 为核心功能的社交产品.另外也有一些应用虽然IM功能不是核心,但IM能力也是其整个应用极其重要的 ...
最新文章
- winrunner事务概念的代码应用(毫秒级)
- java和python哪个好就业2020-java和python哪个的前途更好?
- Python 学习笔记(1)Hello Python
- commonjs是什么_JavaScript模块化标准CommonJS/AMD/CMD/UMD/ES6Module的区别
- c++ 航空管理系统_浅谈航站楼能源管理系统的设计与应用
- 使用Frigga实现WEB方式对服务的监控
- R语言数据分析 | 谱系图与聚类分析
- CorelDRAW入门教程-用CDR制作漂亮小雨伞
- vue填坑之全局引入less,scss,styl文件
- 无线网为何显示无法上网络连接服务器,wlan显示已连接不可上网怎么办_wlan显示已连接但无法访问互联网怎么解决...
- UVALive 4670 Dominating Patterns(AC自动机)
- 博客总纲 博客目录V1
- android 筛选电影,Movie - 该看什么电影呢?这几个小程序或许能给你一个选择 - Android 应用 - 【最美应用】...
- Proxmox VE
- 安装宝塔远程工具流程
- python关于FIFA球员的数据分析
- NOI的1.8.20反反复复
- 计算机第一课 纪律 教案,七年级下信息技术第一单元第一课教案
- 迅雷下载原理的源代码(linux c)
- Guitar Pro8吉他谱中文正式版