本文援用了沈剑《如何保障IM实时音讯的“时序性”与“一致性”?》一文的图片和内容(因为太懒,图没从新画),原文链接在文末。

1、引言

本文接上篇《零根底IM开发入门(三):什么是IM零碎的可靠性?》,解说IM零碎中音讯时序的一致性问题。

所谓的一致性,在IM中通常指的是音讯时序的一致性,那就是:

  • 1)聊天音讯的上下文连续性;
  • 2)聊天音讯的相对工夫序。

再具体一点,IM音讯的一致性体现在:

  • 1)单聊时:要保障发送方收回聊天音讯的程序与接管方看到的程序统一;
  • 2)群聊时:要保障所有群员看到的聊天音讯,与发送者收回音讯时的相对工夫序是统一的。

IM零碎中音讯时序的一致性问题是个看似简略,实则十分有难度的技术热点话题之一,本文尽量以艰深简显的文字为你解说IM音讯时序一致性问题的产品意义、产生起因、解决思路等。

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

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

2、系列文章

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

3、音讯时序的一致性,对于IM的意义

现如今,因为挪动互联网的遍及,现代人的理论社交关系,简直齐全是靠IM这种即时通讯社交工具所组织起来的,IM这种工具的重要性显而易见。

IM在现代人的生存中,越来越重要,但也越来平时。当初想分割一个人,第一工夫想到的不是打个电话,而是发个“微信”或“QQ”。是的,IM这玩意承载的意义越来越多。

音讯时序的一致性问题,对于IM的意义,毫无疑问带来的不只是简简单单的所谓用户体验问题。咱们来看看例子。

假如:你跟女神的表白正进入到要害阶段,聊着聊着就因为这烂IM,导致聊天音讯前言不搭后语,此刻1000公里外你的女神真一脸蒙逼的盯着手机看你的“醉话”,结果是如许重大——这半年来的“舔狗”生存、忍无可忍,算是白白被程序员这群“格子衫”、“地中海”们给祸患了。

再往重大了说,就因为这烂IM,让你失去了这难得的借助女神低劣基因,革新家族后辈颜值的绝佳机会,无不让人痛心疾首。。。

下面这个例子,说的还只是单聊,如果是群聊,则问题可能还会被有限放大:试想一个技术交换群,正在强烈的争吵着“php是世界最好语言”这种话题的时候,突然就想砸手机了,不是因为吵的太凶,而因为音讯程序全乱齐全没法看,曾经重大影响键盘侠们踊跃发表集体意见了。

4、凭什么说保障音讯时序的一致性很艰难?

4.1 根本认知

在一般IM用户的眼里,音讯无非是从一台手机传递到另一台手机而已,保障时序有何艰难?

是的,普通用户这么认为,从技术上讲,他只是单纯的将IM音讯的收发过程了解为单线程的工作模式而已。

实际上,在IM这种高性能场景下,服务端为了谋求高吞吐、高并发,用到了多线程、异步IO等等技术。

在这种状况下,“高并发”与“程序”对于IM服务端来说,原本就是矛盾的,这就有点鱼与熊掌的滋味了(两者很难兼得)。

所以,要实现IM场景下的音讯时序一致性,须要做出衡量,而且要思考的技术维度相当多。这就导致具体技术施行起来没有固定的套路,而因为开发者技术能力的参差不齐,也就使得很多IM零碎在理论的成果上会有较大问题,对于用户而言也将间接在产品体验上反馈进去。

上面将具体阐明技术难点所在。

4.2 没有全局时钟

如上图所示,一个真正堪用的生产零碎,显示不可能所有服务都跑在一台服务器上,分布式环境是必定的。

那么:在分布式环境下,客户端+服务端后盾的各种后盾服务,都各自散布在不同的机器上,机器之间都是应用的本地时钟,没有一个所谓的“全局时钟”(也没方法做到真正的全局时钟),那么所谓的音讯时序也就没有真正意义上的时序基准点。所以音讯时序问题显然不是“本地工夫”能够齐全决定的。

4.3 多发送方问题

服务端分布式的状况下,不能用“本地工夫”来保障时序性,那么是否用接管方本地工夫示意时序呢?

遗憾的是,因为多个客户端的存在(比方群聊时),即便是一台服务器的本地工夫,也无奈示意“相对时序”。

如上图所示:相对时序上,APP1先收回msg1,APP2后收回msg2,都发往服务器web1,网络传输是不能保障msg1肯定先于msg2达到的,所以即便以一台服务器web1的工夫为准,也不能精准形容msg1与msg2的相对时序。

4.4 多接管方问题

多发送方不能保障时序,假如只有一个发送方,是否用发送方的本地工夫示意时序呢?遗憾的是,因为多个接管方的存在,无奈用发送方的本地工夫,示意“相对时序”。

如上图,相对时序上,web1先收回msg1,后收回msg2,因为网络传输及多接管方的存在,无奈保障msg1先被接管到先被解决,故也无奈保障msg1与msg2的解决时序。

4.5 网络传输与多线程问题

既然多发送方与多接管方都难以保障相对时序,那么假如只有繁多的发送方与繁多的接管方,是否保障音讯的相对时序一致性呢?

论断是乐观的,因为网络传输与多线程的存在,这依然不行。

如上图所示,web1先收回msg1、后收回msg2,即便msg1先达到(网络传输其实还不能保障msg1先达到),因为多线程的存在,也不能保障msg1先被解决完。

5、如何保障相对的音讯时序一致性?

通过上一章内容的总结,咱们曾经对IM中音讯时序一致性问题所产生的原因,有了较为粗浅的意识。

从纯技术的角度来说,假如:

  • 1)只有一个发送方;
  • 2)一个接管方;
  • 3)上下游连贯只有一条socket连贯;
  • 4)通过阻塞的形式通信。

这样的状况下,难道不能保障先收回的音讯被先解决,进而被先展现给音讯的接收者吗?

是的,能够!

但理论生产状况下不太可能呈现这种IM零碎,必竟单发送方、单接管方、单socket连贯、阻塞形式,这样的IM一旦做进去,产品经理会立马死给你看。。。

6、实用的优化思路

6.1 一对一单聊的音讯一致性保障思路

假如两人一对一聊天,发送方A顺次收回了msg1、msg2、msg3三条音讯给接管方B,这三条音讯该怎么保障显示时序的一致性(发送与显示的程序统一)?

咱们晓得,发送方A顺次收回的msg1、msg2、msg3三条音讯,到底服务端后,再由服务端直达收回时,这个程序因为多线程的网络的问题,是有可能乱序的。

那么后果就可能是这样:

如上图所示,会呈现与收回时的音讯时序不统一问题(收到的音讯程序是:msg3、msg1、msg2)。

不过,实际上一对一聊天的两个人,并不需要全局音讯时序的统一(因为聊天只在两人的同一会话在产生),只须要对于同一个发送方A,发给B的音讯时序统一就行了。

常见优化计划,在A往B收回的音讯中,加上发送方A本地的一个相对时序(比方本机工夫戳),来示意接管方B的展示时序。

那么当接管方B收到音讯后,即便极其状况下音讯可能存在乱序达到,但因为这个乱序的时间差对于普通用户来说体感是很短的,在UI展示层依照音讯中自带的相对时序排个序后再显示,用户其实是没有太多感知的。

6.2 多对多群聊的音讯一致性保障思路

假如N个群友在一个IM群里聊天,应该怎么保障所有群员收到音讯的显示时序一致性呢?

首先:不能像一对聊天那样利用发送方的相对时序来保障音讯程序,因为群聊发送方不单点,工夫也不统一。

或者:咱们能够利用服务器的单点做序列化。

如上图所示,此时IM群聊的发送流程为:

  • 1)sender1收回msg1,sender2收回msg2;
  • 2)msg1和msg2通过接入集群,服务集群;
  • 3)service层到底层拿一个惟一seq,来确定接管方展现时序;
  • 4)service拿到msg2的seq是20,msg1的seq是30;
  • 5)通过投递服务讲音讯给多个群友,群友即便接管到msg1和msg2的工夫不同,但能够对立依照seq来展示。

这个办法:

  • 1)长处是:能实现所有群友的音讯展现时序雷同;
  • 2)毛病是:这个生成全局递增序列号的服务很容易成为零碎瓶颈。

还有没有进一步的优化办法呢?

从技术角度看:群音讯其实也不必保障全局音讯序列有序,而只有保障一个群内的音讯有序即可,这样的话,“音讯id序列化”就成了一个很好的思路。

上图这个计划中,service层不再须要去一个对立的后端拿全局seq(序列号),而是在service连接池层面做细小的革新,保障一个群的音讯落在同一个service上,这个service就能够用本地seq来序列化同一个群的所有音讯,保障所有群友看到音讯的时序是雷同的。

对于IM的零碎架构下应用怎么样实现音讯序列化,或者说全局音讯ID的生成计划,这又是另一个很热门的技术话题。

有趣味,能够深刻浏览上面这个系列:

《IM音讯ID技术专题(一):微信的海量IM聊天音讯序列号生成实际(算法原理篇)》
《IM音讯ID技术专题(二):微信的海量IM聊天音讯序列号生成实际(容灾计划篇)》
《IM音讯ID技术专题(三):解密融云IM产品的聊天音讯ID生成策略》
《IM音讯ID技术专题(四):深度解密美团的分布式ID生成算法》
《IM音讯ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》
《IM音讯ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》

这个系列中,尤其微信的趋势递增ID生成思路(留神:趋势递增不是严格递增,趋势递增意味着中问有ID被跳过也没事),对于分布式IM的音讯ID来说是十分切实可行的。

是的,对于IM零碎来说,相对意义上的时序很难保障,但通过服务端生成的枯燥递增音讯ID的形式,利用递增ID来保障时序性,也是一个很可性的计划。

7、小结一下

IM零碎架构下,音讯的相对时序是很艰难的,起因多种多样,比方:没有全局时钟、多发送方、多接管方、多线程、网络传输不确定性等。

一对一单聊时,其实只须要保障收回的时序与接管的时序统一,就根本能让用户感觉不到乱序了。

多对多的群聊状况下,保障同一群内的所有接管方音讯时序统一,也就能让用户感觉不到乱序了,办法有两种,一种单点相对时序,另一种实现音讯id的序列化(也就是实现一种全局递增音讯ID)。

8、参考资料

[1] 如何保障IM实时音讯的“时序性”与“一致性”?,作者:沈剑
[2] 一个低成本确保IM音讯时序的办法探讨,作者:封宇

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

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

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

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