本文内容和编写思路是基于邓昀泽的“大规模并发IM服务架构设计”、“IM的弱网场景优化”两文的提纲进行的,感激邓昀泽的自私分享。
1、引言
接上篇《一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等》,本文次要聚焦这套亿级用户的IM架构的一些比拟细节但很重要的热门问题上,比方:音讯可靠性、音讯有序性、数据安全性、挪动端弱网问题等。
以上这些热门IM问题每个话题其实都能够独自成文,但限于文章篇幅,本文不会一一问题具体深刻地探讨,次要以抛砖引玉的形式疏导阅读者了解问题的要害,并针对问题提供专项钻研文章链接,不便有选择性的深刻学习。心愿本文能给你的IM开发带来一些好处。
本文已同步公布于“即时通讯技术圈”公众号,欢送关注。公众号上的链接是:点此进入。
2、系列文章
为了更好以进行内容出现,本文拆分两了高低两篇。
本文是2篇文章中的第2篇:
《一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等》
《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》(本文)
本篇次要聚焦这套亿级用户的IM架构的一些比拟细节但很重要的热门问题上。
3、音讯可靠性问题
音讯的可靠性是IM零碎的典型技术指标,对于用户来说,音讯能不能被牢靠送达(不丢音讯),是应用这套IM的信赖前提。
换句话说,如果这套IM零碎不能保障不丢音讯,那相当于发送的每一条音讯都有被失落的概率,对于用户而言,肯定会不会“释怀”地应用它,即“不信赖”这套IM。
从产品经理的角度来说,有这样的技术阻碍存在,再怎么费劲的推广,最终用户都会很快散失。所以一套IM如果不能保障音讯的可靠性,那问题是很重大的。
PS:如果你对IM音讯可靠性的问题还没有一个直观的映象的话,通过《零根底IM开发入门(三):什么是IM零碎的可靠性?》这篇文章能够通俗易懂的了解它。
如上图所示,音讯可靠性次要依赖2个逻辑来保障:
- 1)上行音讯可靠性;
- 2)上行音讯可靠性。
1)针对上行音讯的可靠性,能够这样的思路来解决:
用户发送一个音讯(假如协定叫PIMSendReq),用户要给这个音讯设定一个本地ID,而后期待服务器操作实现给发送者一个PIMSendAck(本地ID统一),通知用户发送胜利了。
如果期待一段时间,没收到这个ACK,阐明用户发送不胜利,客户端SDK要做重试操作。
2)针对上行音讯的可靠性,能够这样的思路来解决:
服务收到了用户A的音讯,要把这个音讯推送给B、C、D 3集体。假如B长期掉线了,那么在线推送很可能会失败。
因而确保上行可靠性的外围是:在做推送前要把这个推送申请缓存起来。
这个缓存由存储系统来保障,MsgWriter要保护一个(离线音讯列表),用户的一条音讯,要同时写入B、C、D的离线音讯列表,B、C、D收到这个音讯当前,要给存储系统一个ACK,而后存储系统把音讯ID从离线音讯列表里拿掉。
针对音讯的可靠性问题,具体的解决思路还能够从另一个维度来思考:即实时音讯的可靠性和离线音讯的可靠性。
有趣味能够深刻读一读这两篇:
《IM音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递》
《IM音讯送达保障机制实现(二):保障离线音讯的牢靠投递》
而对于离线音讯的可靠性来说,单聊和群聊又有很大区别,无关群聊的离线音讯牢靠投递问题,能够深刻读一读《IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》。
4、音讯有序性问题
音讯的有序性问题是分布式IM零碎中的另一个技术“硬骨头”。
因为是分布式系统,客户端和服务器的时钟可能是不同步的。如果简略依赖某一方的时钟,就会呈现大量的音讯乱序。
比方只依赖客户端的时钟,A比B工夫晚30分钟。所有A给B发消息,而后B给A回复。
发送程序是:
客户端A:“XXX”
客户端B:“YYY”
接管方的排序就会变成:
客户端B:“YYY”
客户端A:“XXX”
因为A的工夫晚30分钟,所有A的音讯都会排在前面。
如果只依赖服务器的时钟,也会呈现相似的问题,因为2个服务器工夫可能也不统一。尽管客户端A和客户端B时钟统一,然而A的音讯由服务器S1解决,B的音讯由服务器S2解决,也会导致同样音讯乱序。
为了解决这种问题,我的思路是通过能够做这样一系列的操作来实现。
1)服务器工夫对齐:
这部分就是后端运维的锅了,由系统管理员来尽量保障,没有别的招儿。
2)客户端通过工夫调校对齐服务器工夫:
比方:客户端登录当前,拿客户端工夫和服务器工夫做差值计算,发送音讯的时候思考这部分差值。
在我的im架构里,这个能把工夫对齐到100ms这个级,差值再小的话就很艰难了,因为协定在客户端和服务器之间传递速度RTT也是不稳固的(网络传输存在不可控的提早危险嘛)。
3)音讯同时带上本地工夫和服务器工夫:
具体能够这样的解决:排序的时候,对于同一个人的音讯,依照音讯本地工夫来排;对于不同人的音讯,依照服务器工夫来排,这是插值排序算法。
PS:对于音讯有序性的问题,显然也不是下面这三两句话能讲的分明,如果你想更艰深一了解它,能够读一读《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》。
另外:从技术实际可行性的角度来说,《一个低成本确保IM音讯时序的办法探讨》、《如何保障IM实时音讯的“时序性”与“一致性”?》这两篇中的思路能够借鉴一下。
实际上,音讯的排序问题,还能够从音讯ID的角度去解决(也就是通过算法让音讯ID产生程序性,从而依据音讯ID就能达到音讯排序的目标)。
无关程序的音讯ID算法问题,这两篇十分值得借鉴:《IM音讯ID技术专题(一):微信的海量IM聊天音讯序列号生成实际(算法原理篇)》、《IM音讯ID技术专题(三):解密融云IM产品的聊天音讯ID生成策略》,我就不废话了。
5、音讯已读同步问题
音讯的已读未读性能,如下图所示:
上图就是钉钉中的已读未读音讯。这在企业IM场景下十分有用(因为做领导的都喜爱,你懂的)。
已读未读性能,对于一对一的单聊音讯来说,还比拟好了解:就是多加一条对应的回执息(当用户浏览这条音讯时发回)。
但对于群聊这说,这一条音讯有多少人已读、多少人未读,想实现这个成果,那就真的有点麻烦了。对于群聊的已读未读性能实现逻辑,这里就不开展了,有趣味能够读一下这篇《IM群聊音讯的已读回执性能该怎么实现?》。
回归到本节的主题“已读同步”的问题,这显示难度又进一级,因为已读未读回执不只是针对“账号”,当初还要细分到“同一账号在不同端登陆”的状况,对于已读回执的同步逻辑来说,这就有点复杂化了。
在这里,依据我这边IM架构的实践经验,提供一些思路。
具体来说就是:用户可能有多个设施登录同一个账户(比方:Web PC和挪动端同时登陆),这种状况下的已读未读性能,就须要来实现已读同步,否则在设施1看过的音讯,设施2看到仍然是未读音讯,从产品的角度来说,这就影响用户体验了。
对于我的im架构来说,已读同步次要依赖2个逻辑来保障:
- 1)同步状态保护,为用户的每一个Session,保护一个工夫戳,保留最初的读音讯工夫;
- 2)如果用户关上了某个Session,且用户有多个设施在线,发送一条PIMSyncRead音讯,告诉其它设施。
6、数据安全问题
6.1 根底
IM零碎架构中的数据安全比个别零碎要简单一些,从通信的角度来说,它波及到socket长连贯通信的安全性和http短连贯的两重安全性。而随着IM在挪动端的风行,又要在安全性、性能、数据流量、用户体验这几个维度上做衡量,所以想要实现一套欠缺的IM平安架构,要面临的挑战是很多的。
IM零碎架构中,所谓的数据安全,次要是通信安全和内容平安。
6.2 通信安全
所谓的通信安全,这就要了解IM通信的服务组成。
目前来说,一个典型的im零碎,次要由两种通信服务组成:
- 1)socket长连贯服务:技术上也就是少数人耳熟能详的网络通信这一块,再细化一点也就是tcp、udp协定这一块;
- 2)http短连贯服务:也就是最罕用的http rest接口那些。
对于晋升长连贯的安全性思路,能够深刻浏览《通俗易懂:一篇把握即时通讯的音讯传输平安原理》。另外,微信团队分享的《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》一文,也十分有参考意义。
如果是通信安全级别更高的场景,能够参考《即时通讯平安篇(二):探讨组合加密算法在IM中的利用》,文中对于组合加密算法的应用思路十分不错。
至于短连贯安全性,大家就很相熟了,开启https少数状况下就够用了。如果对于https不甚了解,能够从这几篇开始:《一文读懂Https的安全性原理、数字证书、单项认证、双项认证等》、《即时通讯平安篇(七):如果这样来了解HTTPS,一篇就够了》。
6.3 内容平安
这个可能不太好了解,下面既然实现了通信安全,那为什么还要纠结“内容平安”?
咱们理解一下所谓的密码学三大作用:加密( Encryption)、认证(Authentication),鉴定(Identification) 。
具体来说就是:
加密:避免好人获取你的数据。
认证:避免好人批改了你的数据而你却并没有发现。
鉴权:避免好人混充你的身份。
在上节中,歹意攻击者如果在通信环节绕开或冲破了“鉴权”、“认证”,那么依赖于“鉴权”、“认证”的“加密”,实际上也有可有被破解。
针对上述问题,那么咱们须要对内容进行更加平安独立的加密解决,就这是所谓的“端到端加密”(E2E)。
比方,那个号称无奈被破解的IM——Telegram,实际上就是应用了端到端加密技术。
对于端到端加密,这里就不深入探讨,这里有两篇文章有趣味地能够深刻浏览:
《挪动端平安通信的利器——端到端加密(E2EE)技术详解》
《简述实时音视频聊天中端到端加密(E2EE)的工作原理》
7、雪崩效应问题
在分布式的IM架构中,存在雪崩效应问题。
咱们晓得,分布式的IM架构中,为了高可用性,用户每次登陆都是依据负载平衡算法调配到不同的服务器。那么问题就来了。
举个例子:假如有5个机房,其中A机房故障,导致这个机房先前服务的用户都跑去B机房。B机房不堪重负也解体了,A+B的用户跑去机房C,连锁反应会导致所有服务挂掉。
避免雪崩效应须要在服务器架构,客户端链接策略上有一些配合的解决方案。服务器须要无限流能力作为根底,次要是限度总服务用户数和短时间链接用户数。
在客户端层面,发现服务断开之后要有一个策略,避免大量用户同一时间去链接某个服务器。
通常有2种计划:
- 1)退却:重连之间设置一个随机的距离;
- 2)LBS:跟服务器申请重连的新的服务器IP,而后由LBS服务去升高短时间调配到同一个服务器的用户量。
这2种计划互不抵触,能够同时做。
8、弱网问题
8.1 弱网问题的起因
鉴于现在IM在挪动端的风行,弱网是很常态的问题。电梯、火车上、开车、地铁等等场景,都会遇到显著的弱网问题。
那么为什么会呈现弱网问题?
要答复这个问题,那就须要从无线通信的原理下来寻找答案。
因为无线通信的品质受制于很多方面的因素,比方:无线信号强弱变动快、信号烦扰、通信基站散布不均、挪动速度太快等等。要说分明这个问题,那就真是三天三夜都讲不完。
有趣味的读者,肯定要仔细阅读上面这几篇文章,相似的跨学科科谱式文章并不多见:
《IM开发者的零根底通信技术入门(十一):为什么WiFi信号差?一文即懂!》
《IM开发者的零根底通信技术入门(十二):上网卡顿?网络掉线?一文即懂!》
《IM开发者的零根底通信技术入门(十三):为什么手机信号差?一文即懂!》
《IM开发者的零根底通信技术入门(十四):高铁上无线上网有多难?一文即懂!》
弱网问题是挪动端APP的必修课,上面这几篇总结也值得借鉴:
《挪动端IM开发者必读(一):通俗易懂,了解挪动网络的“弱”和“慢”》
《挪动端IM开发者必读(二):史上最全挪动弱网络优化办法总结》
《古代挪动端网络短连贯的优化伎俩总结:申请速度、弱网适应、平安保障》
《百度APP挪动端网络深度优化实际分享(三):挪动端弱网优化篇》
8.2 IM针对弱网问题的解决
对于IM来说,弱网问题并不是很简单,外围是做好音讯的重发、排序以及接收端的重试。
为了解决好弱网引发的IM问题,通常能够通过以下伎俩改善:
- 1)音讯主动重发;
- 2)离线音讯接管;
- 3)重发消息排序;
- 4)离线指令解决。
上面将逐个展开讨论。
8.3 音讯主动重发
坐地铁的时候,常常遇到列车开起来当前,网络断开,发送音讯失败。
这时候产品有2种表现形式:
- a、间接通知用户发送失败;
- b、放弃发送状态,主动重试3-5次(3分钟)当前通知用户发送失败。
显然:主动重试失败当前再通知用户发送失败体验要好很多。尤其是在网络闪断状况下,重试成功率很高,很可能用户基本感知不到有发送失败。
从技术上:客户端IMSDK要把每条音讯的状态监控起来。发送音讯不能简略的调用一下网络发送申请,而是要有一个状态机,治理几个状态:初始状态,发送中,发送失败,发送超时。对于失败和超时的状态,要启用重试机制。
这里还有一篇对于重试机制设计的探讨帖子,有趣味能够看看:《齐全自已开发的IM该如何设计“失败重试”机制?》。
《IM音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递》一文中对于音讯超时与重传机制的实现思路,也能够参考一下。
8.4 离线音讯接管
古代IM是没有“在线”这个状态的,不须要给用户这个信息。然而从技术的层面,用户掉线了还是要正确的去感知的。
感知办法有几条:
- a、信令长连贯状态:如果长时间没收到到服务器的心跳反馈,阐明掉线了;
- b、网络申请失败次数:如果屡次网络申请失败,阐明”可能“掉线了;
- c、设施网络状态检测:间接检测网卡状态就好,个别Android/iOS/Windows/Mac都有相应零碎API。
正确检测到网络状态当前,发现网络从”断开到复原“的切换,要去被动拉取离线阶段的音讯,就能够做到弱网状态不丢音讯(从服务器的离线音讯列表拉取)。
下面文字中提到的网络状态的确定,波及到IM里网络连接检查和保活机制问题,是IM里比拟头疼的问题。
一不小心,又踩进了IM网络保活这个坑,我就不在这里开展,有趣味肯定要读读上面的文章:
《为何基于TCP协定的挪动端IM依然须要心跳保活机制?》
《一文读懂即时通讯利用中的网络心跳包机制:作用、原理、实现思路等》
《微信团队原创分享:Android版微信后盾保活实战分享(网络保活篇)》
《挪动端IM实际:实现Android版微信的智能心跳机制》
《挪动端IM实际:WhatsApp、Line、微信的心跳策略剖析》
8.5 重发消息排序
弱网逻辑的另一个坑是音讯排序。
如果有A、B、C 3条音讯,A、C发送胜利,B发送的时候遇到了网络闪断,B触发主动重试。
那么接管方的接管程序应该是 A B C还是A C B呢?我察看过不同的IM产品,解决逻辑各不相同,这个大家有趣味能够去玩一下。
这个解决办法是要依赖上一篇服务架构里提到的差值排序,同一个人收回的音讯,排序按音讯附带的本地工夫来排。不同人的音讯,依照服务器工夫排序。
具体我这边就不再得复,能够回头看看本篇中的第四节“4、音讯有序性问题”。
8.6 离线指令解决
局部指令操作的时候,网络可能呈现了问题,等网络复原当前,要主动同步给服务器。
举一个例子,大家能够试试手机设置为航行模式,而后在微信里删除一个联系人,看看能不能删除。而后从新关上网络,看看这个数据会不会同步到服务器。
相似的逻辑也实用于已读同步等场景,离线状态看过的信息,要正确的跟服务器同步。
8.7 小结一下
IM的弱网解决,其实绝对还是比较简单的,基本上主动重试+音讯状态就能够解决绝大部分的问题了。
一些细节解决也并不简单,次要起因是IM的音讯量比拟小,网络复原后能疾速的复原操作。
视频会议在弱网下的逻辑,就要简单的多了。尤其是高丢包的弱网环境下,要尽力去保障音视频的流畅性。
9、本文小结
《一套亿级用户的IM架构技术干货》这期文章的高低两篇就这么侃完了,上篇波及到的IM架构问题倒还好,下篇一不小心又带出了IM里的各种热门问题“坑”,搞IM开发直是一言难尽。。。
倡议IM开发的入门敌人们,如果想要系统地学习挪动端IM开发的话,应该去读一读我整顿的那篇IM开发“从入门到放弃”的文章(哈哈哈),就是这篇《新手入门一篇就够:从零开发挪动端IM》。具体我就不再开展了,不然这篇幅又要刹不住车了。。。
10、参考资料
[1] 大规模并发IM服务架构设计
[2] IM的弱网场景优化
[3] 零根底IM开发入门(三):什么是IM零碎的可靠性?
[4] IM音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递
[5] IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递
[6] 即时通讯平安篇(二):探讨组合加密算法在IM中的利用
[7] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
附录:更多IM开发文章汇总
《零根底IM开发入门(一):什么是IM零碎?》
《零根底IM开发入门(二):什么是IM零碎的实时性?》
《IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》
《IM开发干货分享:有赞挪动端IM的组件化SDK架构设计实际》
《IM开发宝典:史上最全,微信各种性能参数和逻辑规定材料汇总》
《IM开发干货分享:我是如何解决大量离线音讯导致客户端卡顿的》
《从客户端的角度来谈谈挪动端IM的音讯可靠性和送达机制》
《腾讯技术分享:社交网络图片的带宽压缩技术演进之路》
《挪动端IM中大规模群音讯的推送如何保障效率、实时性?》
《挪动端IM开发须要面对的技术问题》
《开发IM是本人设计协议用字节流好还是字符流好?》
《请问有人晓得语音留言聊天的支流实现形式吗?》
《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》
《IM群聊音讯如此简单,如何保障不丢不重?》
《谈谈挪动端 IM 开发中登录申请的优化》
《挪动端IM登录时拉取数据如何作到省流量?》
《通俗易懂:基于集群的挪动端IM接入层负载平衡计划分享》
《微信对网络影响的技术试验及剖析(论文全文)》本文已同步公布于“即时通讯技术圈”公众号。
▲ 本文在公众号上的链接是:点此进入。同步公布链接是:http://www.52im.net/thread-3445-1-1.html