本文共 4115 字,大约阅读时间需要 13 分钟。
原文地址:
本文的上篇《》中,我们讨论了在线实时消息的投递可以通过应用层的确认、发送方的超时重传、接收方的去重等手段来保证业务层面消息的不丢不重。
但实时在线投递针对的是消息收发双方都在线的情况(如当发送方用户A发送消息给接收方用户B时,用户B是在线的),那如果消息的接收方用户B不在线,系统是如何保证消息的可达性的呢?这就是本文要讨论的问题。(本文同步发布于:)- 即时通讯开发交流群: [推荐]
- 移动端IM开发推荐文章:《》
本文是讨论IM消息送达保证系列文章中的第2篇,总目录如下:
另外,如果您正在查阅移动端IM开发资料,推荐阅读《》。
如上图所述,通常此类情况下消息的发送流程如下:
① 存储离线消看书的表主要字段大致如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 | -- 消息接收者ID receiver_uid varchar (50), -- 消息的唯一指纹码(即消息ID),用于去重等场景,单机情况下此id可能是个自增值、分布式场景下可能是类似于UUID这样的东西 msg_id varchar (70), -- 消息发出时的时间戳(如果是个跨国IM,则此时间戳可能是GMT-0标准时间) send_time time , -- 消息发送者ID sender_uid varchar (50), -- 消息类型(标识此条消息是:文本、图片还是语音留言等) msg_type int , -- 消息内容(如果是图片或语音留言等类型,由此字段存放的可能是对应文件的存储地址或CDN的访问URL) msg_content varchar (1024), … |
1 2 3 | SELECT msg_id, send_time, msg_type, msg_content FROM offline_msgs WHERE receiver_uid = ? and sender_uid = ? |
如果用户B有很多好友,登陆时客户端需要对所有好友进行离线消息拉取,客户端与服务器交互次数就会比较多。
① 拉取好友离线消息的客户端伪代码: 1 2 3 4 5 | // 登陆时所有好友都要拉取 for (all uid in B’s friend-list){ // 与服务器交互 get_offline_msg(B,uid); } |
用户B一次性拉取所有好友发给ta的离线消息,消息量很大时,一个请求包很大、速度慢,容易卡顿怎么办?
正如上图所示,我们可以分页拉取:根据业务需求,先拉取最新(或者最旧)的一页消息,再按需一页页拉取,这样便能很好地解决用户体验问题。如何保证可达性,上述步骤第三步执行完毕之后,第四个步骤离线消息返回给客户端过程中,服务器挂点,路由器丢消息,或者客户端crash了,那离线消息岂不是丢了么(数据库已删除,用户还没收到)?
确实,如果按照上述的1、2、3、4步流程,的确是的,那如何保证离线消息的绝对可靠性、可达性? 如同在线消息的应用层ACK机制一样,离线消息拉时,不能够直接删除数据库中的离线消息,而必须等应用层的离线消息ACK(说明用户B真的收到离线消息了),才能删除数据库中的离线消息。这个应用层的ACK可以通过实时消息通道告之服务端,也可以通过服务端提供的REST接口,以更通用、简单的方式通知服务端。如果用户B拉取了一页离线消息,却在ACK之前crash了,下次登录时会拉取到重复的离线消息么?
确实,拉取了离线消息却没有ACK,服务器不会删除之前的离线消息,故下次登录时系统层面还会拉取到。但在业务层面,可以根据msg_id去重。SMC理论:系统层面无法做到消息不丢不重,业务层面可以做到,对用户无感知。 优化后的拉取过程,如下图所示:假设有N页离线消息,现在每个离线消息需要一个ACK,那么岂不是客户端与服务器的交互次数又加倍了?有没有优化空间?
如上图所示,不用每一页消息都ACK,在拉取第二页消息时相当于第一页消息的ACK,此时服务器再删除第一页的离线消息即可,最后一页消息再ACK一次(实际上:最后一页拉取的肯定是空返回,这样可以极大地简化这个分页过程,否则客户端得知道当前离线消息的总页数,而由于消息读取延迟的存在,这个总页数理论上并非绝对不变,从而加大了数据读取不一致的可能性)。这样的效果是,不管拉取多少页离线消息,只会多一个ACK请求,与服务器多一次交互。正如本文中所列举的问题所描述的那样,保证“离线消息”的可达性比大家想象的要复杂一些,常见优化总结如下:
[1] 网络编程基础资料:
《 - 》 《 - 》 《 - 》 《 - 》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 >> [2] 有关IM/推送的通信格式、协议的选择: 《》 《》 《》 《》 《》 《》 《》 《》 >> [3] 有关IM/推送的心跳保活处理: 《》 《》 《》 《》 《》 《》 《》 >> [4] 有关WEB端即时通讯开发: 《》 《》 《》 《》 《》 《》 >> [5] 有关IM架构设计: 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 >> [6] 有关IM安全的文章: 《》 《》 《》 《》 《》 《》 《》 《》 >> [7] 有关实时音视频开发: 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 >> [8] IM开发综合文章: 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 >> [9] 开源移动端IM技术框架资料: 《》 《》 《》 >> [10] 有关推送技术的文章: 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 《》 >> [11] 更多即时通讯技术好文分类:作者: (点击作者姓名进入Github)
出处: 交流:欢迎加入即时通讯开发交流群 讨论: Jack Jiang同时是和的作者,可前往下载交流。 本博文 欢迎转载,转载请注明出处(也可前往 找到我)。