发布日期:2023-02-03 02:03:27 点击次数:
IM 即时通讯技术在多应用场景下的技术实现,以及性能调优( iOS 视角)(附 PPT 与 2 个半小时视频)
IM 即时通讯技术在多应用场景下的技术实现,以及性能调优( iOS 视角)(附 PPT 与 2 个半小时视频)
IM 即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角)
在 MDCC2016 上我做了关于 IM 相关分享,会上因为有50分钟的时间限制 ,所以有很多东西都没有展开,这篇是演讲稿的博文版本,比会上讲得更为详细。有些演讲时一笔带过的部分,在文中就可以展开讲讲。
我现在任职于LeanCloud(原名AVOS)。LeanCloud 是国内较早提供 IM 服务的 Paas 厂商,提供 IM 相关的 SDK 供开发者使用,现在采纳我们 IM 方案的 APP 有:知乎Live、掌上链家、懂球帝等等,在 IM 方面也积累了一些经验,这次就在这篇博文分享下。
如何在移动网络环境下优化电量,流量,及长连接的健壮性?现在移动网络有2G、3G、4G各种制式,并且随时可能切换和中断,移动网络优化可以说是面向移动服务的共同问题。
如何确保IM系统的整体安全?因为用户的消息是个人隐私,因此要从多个层面来保证IM系统的安全性。
如何应对新的iOS生态下的政策以及结合新技术:比如HTTP/2、IPv6、新的APNs协议等IM电竞APP。
一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
比如中秋节我们要做一个秒杀月饼的页面,要求我们要实时地展示剩余的月饼数量,也就是库存量。这时候如果要求你只能用短轮询或长轮询去做,怎么做呢?
长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管服务端有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止,这就是区别。
(实际开发中不会使用长短轮询来做这种需求,这里仅仅是为了说明两者区别而做的一个例子。)
我们可以看到,发展历史是这样:从长短轮询到长连接,使用 WebSocket 来替代 HTTP。
协商方式不同:一个 TCP 连接是否为长连接,是通过设置 HTTP 的 Connection Header 来决定的,而且是需要两边都设置才有效。而一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
实现方式不同:连接的长短是通过协议来规定和实现的。而轮询的长短,是服务器通过编程的方式手动挂起请求来实现的。
我们以相同的频率 10W/s 去做网络请求, 对比下轮询与 WebSocket 所花费的 Header 流量:
出于兼容性考虑,一般建立 WebSocket 连接也采用 HTTP 请求的方式IM电竞APP,那么从这个角度讲:无论请求如何频繁,都只需要一个 Header。
相同的每秒客户端轮询的次数,当次数高达 10W/s 的高频率次数的时候,Polling 轮询需要消耗665Mbps,而 WebSocket 仅仅只花费了1.526Mbps,将近435倍!!
注:本次投票是发布在微博@iOS程序犭袁,鉴于微博关注机制,本数据只能反映出 IM 技术在 iOS 领域的使用情况,并不能反映出整个IT行业的情况。
IM 协议选择原则一般是:易于拓展,方便覆盖各种业务逻辑,同时又比较节约流量。后一点的需求在移动端 IM 上尤其重要。常见的协议有:XMPP、SIP、MQTT、私有协议。
优点:协议开源,可拓展性强,在各个端(包括服务器)有各种语言的实现,开发者接入方便;
缺点:缺点也是不少,XML表现力弱、有太多冗余信息、流量大,实际使用时有大量天坑。
优点:协议简单,流量少;订阅+推送模式,非常适合Uber、滴滴的小车轨迹的移动。
缺点:它并不是一个专门为 IM 设计的协议,多使用于推送。IM 情景要复杂得多,pub、sub,比如:加入对话、创建对话等等事件。
市面上几乎所有主流IM APP都是是使用私有协议,一个被良好设计的私有协议优点非常明显。优点:高效,节约流量(一般使用二进制协议),安全性高,难以破解;
一个好的协议需要满足如下条件:高效,简洁,可读性好,节约流量,易于拓展,同时又能够匹配当前团队的技术堆栈。基于如上原则,我们可以得出: 如果团队小,团队技术在 IM 上积累不够可以考虑使用 XMPP 或者 MQTT+HTTP 短连接的实现。反之可以考虑自己设计和实现私有协议,这里建议团队有计划地迁移到私有协议上。
这里特别提一下排名第二的 WebSocket ,区别于上面的聊天协议,这是一个传输通讯协议,那为什么会有这么多人在即时通讯领域运用了这一协议?除了上文说的长连接特性外,这个协议 web 原生支持,有很多第三方语言实现,可以搭配 XMPP、MQTT 等多种聊天协议进行使用,被广泛地应用于即时通讯领。
我们专门为社交场景开发的开源组件:ChatKit-OC,star数,1000+。
(这个库,我最近也在优化,打算做成 Lib,支持下 CocoaPods 。希望能帮助大家快速集成直播模块。有兴趣的也欢迎参与进来提 PR)
那么可以看下 Demo 的实现:我们可以看到里面的弹幕、礼物、点赞出心这些都是 IM 系统里的自定义消息。
正如上文所提到的,使用 MQTT 实现最为经济。用社交类、直播类的思路来做,也可以实现,但略显冗余。
Message 在发送后,在服务端维护一个表,一段时间内,比如15秒内没有收到 ack,就认为应用处于离线状态,先将用户踢下线,然后转而进行推送。这里如果出现,重复推送,客户端要负责去重。将 Message 消息相当于服务端发送的 Ping 消息,APP 的 ack 作为 pong。
当 APNs 向你发送了4条推送,但是你的设备网络状况不好,在 APNs 那里下线了,这时 APNs 到你的手机的链路上有4条任务堆积,APNs 的处理方式是,只保留最后一条消息推送给你,然后告知你推送数。那么其他三条消息呢?会被APNs丢弃。
有一些 App 的 IM 功能没有维持长连接,是完全通过推送来实现的,通常情况下,这些 App 也已经考虑到了这种丢推送的情况,这些 App 的做法都是,每次收到推送之后,然后向自己的服务器查询当前用户的未读消息。但是 APNs 也同样无法保证这四条推送能至少有一条到达你的 App。
为什么这么设计?APNs的存储-转发能力太弱,大量的消息存储和转发将消耗 Apple 服务器的资源,可能是出于存储成本考虑,也可能是因为 Apple 转发能力太弱。总之结果就是 APNs 从来不保证消息的达到率。并且设备上线之后也不会向服务器上传信息。
现在我们可以保证消息一定能推送到 APNs 那里,但是 APNs 不保证帮我们把消息投递给用户。
即使搭配了这样的策略:每次收到推送就拉历史记录的消息,一旦消息被 APNs 丢弃,这条消息可能会在几天之后受到了新推送后才被查询到。
APNs 的实现原理决定了:必须每次收到消息后,拉取历史消息。这意味着你无法控制 APP 请求服务端的频率,同一时间十万、百万的请求量都是可能的,这带来的负载以及风险,有时甚至会比轮询还要大。
结论:如果面向的目标用户对消息的及时性并不敏感,可以采用这种方案。比如社交场景。(对消息较为敏感的APP则并不适合,比如:专门为情侣间使用的APP。。。)
在 WebSocket API 中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道IM电竞APP。两者之间就直接可以数据互相传送。
只从 RFC 发布的时间看来,WebSocket要晚很多,HTTP 1.1是1999年,WebSocket 则是12年之后了。WebSocket 协议的开篇就说,本协议的目的是为了解决基于浏览器的程序需要拉取资源时必须发起多个HTTP请求和长时间的轮训的问题而创建的。可以达到支持 iOS,,Web 三端同步的特性。
注:本次投票是发布在微博@iOS程序犭袁,鉴于微博关注机制,本数据只能反映出 IM 技术在 iOS 领域的使用情况,并不能反映出整个IT行业的情况。
【省流量】流量消耗极少,省流量。一条消息数据用Protobuf序列化后的大小是 JSON 的1/10、XML格式的1/20、是二进制序列化的1/10。同 XML 相比, Protobuf 性能优势明显。它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍。
【高效心跳包】同时心跳包协议对IM的电量和流量影响很大,对心跳包协议上进行了极简设计:仅 1 Byte 。
【易于使用】开发人员通过按照一定的语法定义结构化的消息格式,然后送给命令行工具,工具将自动生成相关的类,可以支持java、c++、python、Objective-C等语言环境。通过将这些类包含在项目中,可以很轻松的调用相关方法来完成业务消息的序列化与反序列化工作。语言支持:原生支持c++、java、python、Objective-C等多达10余种语言。 2015-08-27 Protocol Buffers v3.0.0-beta-1中发布了Objective-C(Alpha)版本, 2016-07-28 3.0 Protocol Buffers v3.0.0正式版发布,正式支持 Objective-C。
【可靠】微信和手机 QQ 这样的主流 IM 应用也早已在使用它(采用的是改造过的Protobuf协议)
对数据分别操作100次,1000次,10000次和100000次进行了测试,
数据来自:项目thrift-protobuf-compare,测试项为 Total Time,也就是 指一个对象操作的整个时间,包括创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程。从测试结果可以看到 Protobuf 的成绩很好.
可能会造成 APP 的包体积增大,通过 Google 提供的脚本生成的 Model,会非常“庞大”,Model 一多,包体积也就会跟着变大。
在使用过程中要合理地权衡包体积以及传输效率的问题,据说去哪儿网,就曾经为了减少包体积,进而减少了 Protobuf 的使用。
IM 服务账号密码一旦泄露,危害更加严峻。尤其是对于消息可以漫游的类型。比如:
介绍下我们是如何做到,即使是我们的服务器被攻破,你的用户系统依然不会受到影响:
与用户的用户帐号体系完全隔离,只需要提供一个ID就可以通信,接入方可以对该 ID 进行 MD5 加密后再进行传输和存储,保证开发者用户数据的私密性及安全。
让 APP 支持单点登录,能有限减少盗号造成的安全问题。在 ChatKit-OC 中,我们就默认开启了单点登录功能,以此来提升 APP 的安全性。
这里有必要提一下重连机制的必要性,我们知道 TCP 也有保活机制,但这个与我们在这里讨论的“心跳保活”机制是有区别的。
比如:考虑一种情况,某台服务器因为某些原因导致负载超高,CPU 100%,无法响应任何业务请求,但是使用 TCP 探针则仍旧能够确定连接状态,这就是典型的连接活着但业务提供方已死的状态,对客户端而言,这时的最好选择就是断线后重新连接其他服务器,而不是一直认为当前服务器是可用状态,一直向当前服务器发送些必然会失败的请求。
大多数的移动网络(3G)并不允许一个给定 IP 地址超过两个的并发 HTTP 请求,既当你有两个针对同一个地址的连接时,再发起的第三个连接总是会超时。而2G网络下这个限定为1个。同一时间发起过多的网络请求不仅不会起到加速的效果,反而有副作用。
另一方面,由于网络连接很是费时,保持和共享某一条连接就是一个不错的选择:比如短时间内多次的HTTP请求。
HTTP/2 是 HTTP 协议发布后的首个更新,于2015年2月17日被批准。它采用了一系列优化技术来整体提升 HTTP 协议的传输性能,如异步连接复用、头压缩等等,可谓是当前互联网应用开发中,网络层次架构优化的首选方案之一。
过短的超时容易导致连接超时的事情频频发生,甚至一直无法连接,而过长的超时则会带来等待时间过长,体验差的问题。就目前来看,对于普通的TCP连接30秒是个不错的超时值,而Http请求可以按照重要性和当前网络情况动态调整超时,尽量将超时控制在一个合理的数值内,以提高单位时间内网络的利用率。
图片格式优化在业界已有成熟的方案,例如 Facebook 使用的 WebP 图片格式,已经被国内众多 App 使用。
微信是不用考虑消息同步问题,因为微信是不存储历史记录的,卸载重装消息记录就会丢失。
所以我们可以采用一个类似 E-Tag、Last-Modified 的本地消息缓存校验机制,具体做法就是,当我们想加载最近10条的聊天记录时,先将本地缓存的最近10条做一个 hash 值,将 hash 值发送给服务端,服务端将服务端的最近十条做一个 hash ,如果一致就返回304。最理想的情况是服务端一直返回304,一直加载本地记录。这样做的好处:
初涉IM,首先我有这么几个问题需要弄明白: Socket 和 WebSocket 有哪些区别和联系? WebSoc...
前言 最近在写一个即时通讯的项目,有一些心得,写出来给大家分享指正一下。 简单描述一下这个项目: 实时查询车辆运行...
2017年2月17日 星期五 农历正月二十一日 “育心丽谦·时间管理100天挑战营第33天 【早起】4:47 【...
《金文诚〈论语〉学习笔记439子张第十九2》 今天是丙申年甲午月戊卯日,五月十一,2016年6月15日星期三。 今...
暗恋是一种什么滋味呢? 是无数次角落里不经意的注视,如青柠般酸涩;还是数不清的完美相遇,似西柚般美好,或许就好像我...
芙蓉难比容颜娇 轻纱独坐谧无扰 如霜娇容轻闭眸 幽兰深谷亦妖娆 青翠杨柳枝下垂 丽人悠...
清明~法定假日3天,对比往年时间算是充裕了很多,给家里打电线点多天蒙蒙亮就起床出发,奈...IM电竞APP