乐趣区

关于即时通讯:零基础IM开发入门三什么是IM系统的可靠性

本文编写时援用了“聊聊 IM 零碎的即时性和可靠性”一文的局部内容和图片,感激原作者。

1、引言

上一篇《零根底 IM 开发入门(二):什么是 IM 零碎的实时性?》讲到了 IM 零碎的“立足”之本——“实时性”这个技术特色,本篇次要解说 IM 零碎中的“可靠性”这个话题,内容尽量做到只讲原理不深刻开展,避开深层次的技术性探讨,确保通俗易懂。


浏览对象:本系列文章次要浏览对象为零 IM 根底的开发者或产品经理,指标是通知你“IM 零碎是什么?”,尽量不深入探讨具体的技术实现,确保通俗易懂,老少皆宜。

如您想从技术维度零碎学习 IM 技术并着手自已的 IM 开发(即解决“IM 零碎要怎么做?”这个疑难),请从此文开始:《新手入门一篇就够:从零开发挪动端 IM》。

学习交换:

  • 即时通讯 / 推送技术开发交换 5 群:215477170[举荐]
  • 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
  • 开源 IM 框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步公布于:http://www.52im.net/thread-3182-1-1.html)

2、系列文章

《零根底 IM 开发入门(一):什么是 IM 零碎?》
《零根底 IM 开发入门(二):什么是 IM 零碎的实时性?》
《零根底 IM 开发入门(三):什么是 IM 零碎的可靠性?》(* 本文)
《零根底 IM 开发入门(四):什么是 IM 零碎的音讯时序一致性?》
《零根底 IM 开发入门(五):什么是 IM 零碎的安全性?(稍后公布)》
《零根底 IM 开发入门(六):什么是 IM 零碎的的心跳机制?(稍后公布)》
《零根底 IM 开发入门(七):如何了解并实现 IM 零碎音讯未读数?(稍后公布)》
《零根底 IM 开发入门(八):如何了解并实现 IM 零碎的多端音讯漫游?(稍后公布)》

3、注释概述

一般来说,IM 零碎的音讯“可靠性”,通常就是指聊天音讯投递的可靠性(精确的说,这个“音讯”是狭义的,因为还存用户看不见的各种指令,为了艰深,统称“音讯”)。

从用户行为来讲,音讯“可靠性”应该分为两种类型:

  • 1)在线音讯的可靠性:即发送音讯时,接管方以后处于“在线”状态;
  • 2)离线音讯的可靠性:即发送音讯时,接管方以后处于“离线”状态。

从具体的技术体现来讲,音讯“可靠性”蕴含两层含意:

  • 1)音讯不丢:这很直白,收回去的音讯不能像进了黑洞一样,一脸懵逼可不行;
  • 2)音讯不重:这是丢音讯的背面,音讯反复了也不能容忍。

对于“音讯不丢”这个特色来说,细化下来,它又蕴含两重含意:

  • 1)已明确被对方收到;
  • 2)已明确未被对方收到。

是的,对于第 1)重含意好了解,第 2)重含意的意思是:当对方没有胜利收到时,你的 im 零碎也必须要感知到,否则,它同样属于被“丢”领域。

总之,一个成型的 im 零碎,必须蕴含这两种音讯“可靠性”逻辑,能力堪用,缺一不可。

音讯的可靠性(不失落、不反复)无疑是 IM 零碎的重要指标,也是 IM 零碎实现中的难点之一。本文以下文字,将从在线音讯的可靠性和离线音讯的可靠性进行探讨。

4、典型的在线音讯收发流程

先看上面这张典型的 im 音讯收发流程:

是的,这是一个典型的服务端中转型 IM 架构。

所谓“服务端中转型 IM 架构”是指:一条音讯从客户端 A 收回后,须要先通过 IM 服务器来进行直达,而后再由 IM 服务器推送给客户端 B,这种模式也是目前最常见的 IM 零碎的音讯散发架构。

你可能会说,IM 不能够是 P2P 模式的吗?是的,目前来说支流 IM 根本都是服务器直达这种形式,P2P 模式在 IM 零碎中用的很少。

起因是以下两个很显著的弊病:

  • 1)P2P 模式下,IM 运营者很容易被用户架空(无奈监管到用户行为,用户涉黄了怕不怕?);
  • 2)P2P 模式下,群聊这种业务状态,很难实现(我要在千人群中发消息给,不可能我自已来散发 1000 次吧)。

话题有点跑偏,咱们回到正题:在下面这张图里,客户 A 发送音讯到服务端、服务端直达音讯给客户 B,假如这两条数据链接中应用的通信协议是 TCP,你认为在 TCP 所谓牢靠传输协定加持下,真的能保障 IM 聊天音讯的可靠性吗?

答案是否定的。咱们持续看下节。

5、TCP 并不能保障在线音讯的“可靠性”

接上节,在一个典型的服务端中转型 IM 架构中,即便应用“牢靠的传输协定”TCP,也不能保障聊天音讯的可靠性。为什么这么说?

要答复这个问题,网上的很多文章,都会从服务端的角度举例:比方音讯发送时操作系统解体、网络闪断、存储故障等等,总之很形象,不太容易了解。

这次咱们从客户端角度来了解,为什么应用了牢靠传输协定 TCP 的状况下 IM 聊天音讯依然不牢靠的问题。

具体来说:如何确保 IM 音讯的可靠性是个绝对简单的话题,从客户端发送数据到服务器,再从服务器送达指标客户端,最终在 UI 胜利展现,其间波及的环节很多,这里只取其中一环「接收端如何确保音讯不失落」来探讨,粗略聊下我接触过的两种设计思路。

说到牢靠送达:第一反馈会联想到 TCP 的可靠性。数据的牢靠送达是个通用性的问题,无论是网络二进制流数据,还是下层的业务数据,都有可靠性保障问题,TCP 作为网络基础设施协定,其可靠性设计的可靠性是毋庸置疑的,咱们就从 TCP 的可靠性说起。

在 TCP 这一层:所有 Sender 发送的数据,每一个 byte 都有标号(Sequence Number),每个 byte 在到达接收端之后都会被接收端返回一个确认信息(Ack Number),二者关系为 Ack = Seq + 1。简略来说,如果 Sender 发送一个 Seq = 1,长度为 100 bytes 的包,那么 receiver 会返回一个 Ack = 101 的包,如果 Sender 收到了这个 Ack 包,阐明数据的确被 Receiver 收到了,否则 Sender 会采取某种策略重发下面的包。

第一个问题是:既然 TCP 自身是具备可靠性的,为什么还会呈现音讯接收端(Receiver)失落音讯的状况?

看下图高深莫测:

(▲ 上图援用自《从客户端的角度来谈谈挪动端 IM 的音讯可靠性和送达机制》)

一句话总结上图的含意:网络层的可靠性不等同于业务层的可靠性。

数据牢靠到达网络层之后,还须要一层层往上移交解决,可能的解决有:

  • 1)安全性校验;
  • 2)binary 解析;
  • 3)model 创立;
  • 4)写 db;
  • 5)存入 cache;
  • 6)UI 展现;
  • 7)以及一些边界问题:比方断网、用户忽然退出登陆、磁盘已满、内存溢出、app 奔溃、忽然关机等等。

我的项目的性能个性越多,网络层往上的解决出错的可能性就越大。

举个最简略的场景为例子:音讯牢靠到达网络层之后,写 db 之前 IM APP 解体(不稀奇,是 App 都有解体的可能),尽管数据在网络层牢靠到达了,但没存进 db,下次用户关上 App 音讯天然就失落了,如果不在业务层再减少可靠性保障(比方:前面要提到的网络层面的音讯重发保障),那么意味着这条音讯对于接收端来说就永远失落了,也就天然不存在“可靠性”了。

从客户端角度了解 IM 的可能性以及解决办法,能够具体浏览:《从客户端的角度来谈谈挪动端 IM 的音讯可靠性和送达机制》,本节援用的是该文中“4、TCP 协定的可靠性之外还会呈现音讯失落?”一节的文字。

6、为在线音讯减少“可靠性”保障

那么怎么在应用层减少可靠性保障呢?

有一个现成的机制可供咱们借鉴:TCP 协定的超时、重传、确认机制。

具体来说就是:

  • 1)在应用层结构一种 ACK 音讯,当接管方正确处理完音讯后,向发送方发送 ACK;
  • 2)如果发送方在超时工夫内没有收到 ACK,则认为音讯发送失败,须要进行重传或其余解决。

减少了确认机制的音讯收发过程如下:

咱们能够把整个过程分为两个阶段。

阶段 1:clientA -> server

  • 1-1:clientA 向 server 发送音讯(msg-Req);
  • 1-2:server 收取音讯,回复 ACK(msg-Ack)给 clientA;
  • 1-3:一旦 clientA 收到 ACK 即可认为音讯已胜利投递,第一阶段完结。

无论 msg- A 或 ack- A 失落,clientA 均无奈在超时工夫内收到 ACK,此时能够提醒用户发送失败,手动进行重发。

阶段 2:server -> clientB

  • 2-1:server 向 clientB 发送音讯(Notify-Req);
  • 2-2:clientB 收取音讯,回复 ACK(Notify-ACk)给 server;
  • 2-3:server 收到 ACK 之后将该音讯标记为已发送,第二阶段完结。

无论 msg- B 或 ack- B 失落,server 均无奈在超时工夫内收到 ACK,此时须要重发 msg-B,直到 clientB 返回 ACK 为止。

对于 IM 聊天音讯的可靠性保障问的深刻探讨,能够详读:《IM 音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递》,该文会深刻探讨这个话题。

7、典型的离线音讯收发流程

说完在线音讯的“可靠性”问题,咱们该理解一下离线音讯了。

7.1 离线音讯的收发也存在“不可靠性”

下图是一张典型的 IM 离线音讯流程图:

如上图所示,和在线音讯收发流程相似。

离线音讯收发流程也可划分为两个阶段:

阶段 1:clientA -> server

  • 1-1:clientA 向 server 发送音讯(msg-Req);
  • 1-2:server 发现 clientB 离线,将音讯存入 offline-DB。

阶段 2:server -> clientB

  • 2-1:clientB 上线后向 server 拉取离线音讯(pull-Req);
  • 2-2:server 从 offline-DB 检索相应的离线音讯推送给 clientB(pull-res),并从 offline-DB 中删除。

显然:离线音讯收发过程同样存在音讯失落的可能性。

举例来说:假如 pull-res 没有胜利送达 clientB,而 offline-DB 中已删除,这部分离线音讯就彻底失落了。

7.2 离线音讯的“可靠性”保障

与在线音讯收发流程相似,咱们同样须要在应用层减少可靠性保障机制。

下图是减少了可靠性保障后的离线音讯收发流程:

与初始的离线音讯收发流程相比,上图减少了 1 -3、2-4、2- 5 步骤:

  • 1-3:server 将音讯存入 offline-DB 后,回复 ACK(msg-Ack)给 clientA,clientA 收到 ACK 即可认为音讯投递胜利;
  • 2-4:clientB 收到推送的离线音讯,回复 ACK(res-Ack)给 server;
  • 2-5:server 收到 res-ACk 后确定离线音讯已被 clientB 胜利收取,此时能力从 offline-DB 中删除。

当然,上述的保障机制,还存在性能优化空间。

当离线音讯的量较大时:如果对每条音讯都回复 ACK,无疑会大大增加客户端与服务器的通信次数。这种状况咱们通常应用批量 ACK 的形式,对多条音讯仅回复一个 ACK。在某尔后 IM 的实现中是将所有的离线音讯按会话进行分组,每组回复一个 ACK,如果某个 ACK 失落,则只须要重传该会话的所有离线音讯。

无关离线音讯的可靠性保障机制的具体探讨,能够详读:《IM 音讯送达保障机制实现(二):保障离线音讯的牢靠投递》、《IM 开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》,这两篇文章能够给你更深刻具体的答案。

8、聊天音讯反复的问题

下面章节中,通过在应用层退出重传、确认机制后,咱们的确是杜绝了音讯失落的可能性。

但因为重试机制的存在,咱们会遇到一个新的问题:那就是同一条音讯可能被反复发送。

举一个最简略的例子:假如 client 胜利收到了 server 推送的音讯,但其后续发送的 ACK 失落了,那么 server 将会在超时后再次推送该音讯,如果业务层不对反复音讯进行解决,那么用户就会看到两条齐全一样的音讯。

音讯去重的形式其实非常简单,个别是依据音讯的惟一标记 (id) 进行过滤。

具体过程在服务端和客户端可能有所不同:

  • 1)客户端:咱们能够通过结构一个 map 来保护已接管音讯的 id,当收到 id 反复的音讯时间接抛弃;
  • 2)服务端:收到音讯时依据 id 去数据库查问,若库中已存在则不进行解决,但依然须要向客户端回复 Ack(因为这条音讯很可能来自用户的手动重发)。

对于音讯的去重问题,在一对一聊天的状况下,逻辑并不简单,但在群聊模式下,会将问题复杂化,无关群聊音讯不丢和去重的具体探讨,能够深刻浏览:《IM 群聊音讯如此简单,如何保障不丢不重?》。

9、本文小结

保障音讯的可靠性是 IM 零碎设计中很重要的一环,能不能做到“音讯不丢”、“音讯不重”,对用户的体验影响极大。

所谓“牢靠的传输协定”TCP 也并不能保障音讯在应用层的可靠性。

咱们个别通过在应用层的 ACK 应答和重传机制,来实现 IM 音讯的可靠性保障。但由此带来的音讯反复问题,须要咱们额定进行解决,最简略的办法就是通过音讯 ID 进行幂等去重。

对于 IM 零碎音讯可靠性的实践根底,咱们就探讨到这里,有疑难的读者,能够在本文开端注意,欢送踊跃探讨。

10、参考资料

[1] IM 音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递

[2] IM 音讯送达保障机制实现(二):保障离线音讯的牢靠投递

[3] IM 开发干货分享:如何优雅的实现大量离线音讯的牢靠投递

[4] 从客户端的角度来谈谈挪动端 IM 的音讯可靠性和送达机制

[5] 聊聊 IM 零碎的即时性和可靠性

[6] 学习笔记 4——IM 零碎如何保障音讯的可靠性

[7] IM 群聊音讯如此简单,如何保障不丢不重?

附录:更多 IM 开发热门技术点

《挪动端 IM 开发者必读(一):通俗易懂,了解挪动网络的“弱”和“慢”》
《挪动端 IM 开发者必读(二):史上最全挪动弱网络优化办法总结》
《古代挪动端网络短连贯的优化伎俩总结:申请速度、弱网适应、平安保障》
《挪动端 IM 中大规模群音讯的推送如何保障效率、实时性?》
《挪动端 IM 开发须要面对的技术问题》
《开发 IM 是本人设计协议用字节流好还是字符流好?》
《请问有人晓得语音留言聊天的支流实现形式吗?》
《如何保障 IM 实时音讯的“时序性”与“一致性”?》
《一个低成本确保 IM 音讯时序的办法探讨》
《IM 单聊和群聊中的在线状态同步应该用“推”还是“拉”?》
《IM 群聊音讯如此简单,如何保障不丢不重?》
《谈谈挪动端 IM 开发中登录申请的优化》
《挪动端 IM 登录时拉取数据如何作到省流量?》
《浅谈挪动端 IM 的多点登录和音讯漫游原理》
《齐全自已开发的 IM 该如何设计“失败重试”机制?》
《微信对网络影响的技术试验及剖析(论文全文)》
《IM 开发基础知识补课(五):通俗易懂,正确理解并用好 MQ 音讯队列》
《微信技术分享:微信的海量 IM 聊天音讯序列号生成实际(算法原理篇)》
《IM 开发基础知识补课(六):数据库用 NoSQL 还是 SQL?读这篇就够了!》
《IM 里“左近的人”性能实现原理是什么?如何高效率地实现它?》
《IM 的扫码登录性能如何实现?一文搞懂支流利用的扫码登录技术原理》
《IM 音讯 ID 技术专题(一):微信的海量 IM 聊天音讯序列号生成实际(算法原理篇)》
《IM 音讯 ID 技术专题(二):微信的海量 IM 聊天音讯序列号生成实际(容灾计划篇)》
《IM 音讯 ID 技术专题(三):解密融云 IM 产品的聊天音讯 ID 生成策略》
《IM 音讯 ID 技术专题(四):深度解密美团的分布式 ID 生成算法》
《IM 音讯 ID 技术专题(五):开源分布式 ID 生成器 UidGenerator 的技术实现》
《IM 音讯 ID 技术专题(六):深度解密滴滴的高性能 ID 生成器(Tinyid)》
《IM 开发宝典:史上最全,微信各种性能参数和逻辑规定材料汇总》

本文已同步公布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3182-1-1.html

退出移动版