本文接上篇《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》,关于移动网络的主要特性,在上篇中已进行过详细地阐述,本文将针对上篇中提到的特性,结合咱们的实践经验,总结了四个方法来追求极致的“爽快”:快链路、轻往复、强监控、多异步,从理论讲到实践、从技术讲到产品,理论联系实际,触类旁通,但愿给您带来启发。
若是您还未阅读完上篇《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》,建议您先行读完后再续本文。
本篇的目的,就是但愿以通俗易懂的语言,帮助移动端IM开发者更好地针对性优化移动网络的各类特性,使得开发出的功能给用户带来更好的使用体验。
本文乃全网同类文章中,惟一内容最全、“粪”量最重者,请作好心理准备耐心读下去,不要辜负做者已打上石膏的双手和用废的键盘。
另外,《现代移动端网络短链接的优化手段总结:请求速度、弱网适应、安全保障》这篇文章也提到了本文所阐述的相关内容,强烈建议阅读。php
学习交流:html
- 即时通信开发交流3群:185926912[推荐]前端
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》程序员
(本文同步发布于:http://www.52im.net/thread-1588-1-1.html)算法
▼ 本文是《移动端IM开发者必读》系列文章的第2篇:
编程
若是您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。后端
1)关于网络通讯的基础文章:
缓存
2)涉及移动端网络特性的文章:
安全
咱们须要有一条(相对)快速、(相对)顺畅、(相对)稳定的网络通道承载业务数据的传输,这条路的最好是传输快、不拥堵、带宽大、收费少。生活中作个类比,咱们计划驱车从深圳到广州,若是想固然走广深高速十之八九要杯具,首先这个高速略显破败更像省道,路况不佳不敢提速;其次这条路上的车时常如过江之鲫,若是身材很差操控不便,根本就快不起来;最后双向六车道虽然勉强能够接受,但收费竟然比广深沿江高速双向八车道还贵;正确的选路方案目前看是走沿江高速,虽然可能要多跑一段里程,可是通行更畅快。
实际上,真实状况要更复杂,就如同上篇中【图二 有线互联网和移动互联网网络质量差别】所示(就是下图),漫漫征途中经常会在高速、国道、省道、田间小道上切换。
<ignore_js_op>
服务器
纯技术活,直接上建议得了,每一个子项争取能大体有个背景交待,若是没说清楚,能够先看看如下资料:
《TCP/IP详解 - 第17章·TCP:传输控制协议》
《TCP/IP详解 - 第18章·TCP链接的创建与终止》
《TCP/IP详解 - 第21章·TCP的超时与重传》
《通俗易懂-深刻理解TCP协议(上):理论基础》
《通俗易懂-深刻理解TCP协议(下):RTT、滑动窗口、拥塞处理》
《理论经典:TCP协议的3次握手与4次挥手过程详解》
《鲜为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)》
《鲜为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)》
《鲜为人知的网络编程(三):关闭TCP链接时为何会TIME_WAIT、CLOSE_WAIT》
《网络编程懒人入门(三):快速理解TCP协议一篇就够》
① 控制传输包大小
控制传输包的大小在1400字节如下。暂时不讲为何这样建议,先举个例子来类比一下,好比一辆大卡车满载肥猪正在高速上赶路,猪笼高高层叠好不壮观,这时前方忽然出现一个隧道限高标识,司机发现卡车超限了,这下咋整。方案一,停车调头从新找路,并且十之八九找不到,最后只能哪来回哪;方案二,把其中一群猪卸下来放本地找人代养,到达目的地卸完货回来再取,你别说,这个机制在TCP/IP协议栈中也有,学名“IP分片”,后面会专门介绍。这个故事侧面证明美国计算机科学家也曾经蹲在高速路边观察生猪超载运输的过程,并饱受启发。且慢,每次遇到问题,想到一些方案后咱们都应该再扪心自问:“还有没有更好的办法呢?”。固然有,参照最近流行的说法,找个台风眼,把猪都赶过去,飞一会就到了,此情此景想一想也是醉了。
回归正题,归纳的说,咱们设定1400这个阈值,目的是减小往复,提升效能。由于TCP/IP网络中也有相似高速限高的规定,若是在超限时想要继续顺畅传输,要么作IP分片要么把应用数据拆分为多个数据报文(意指由于应用层客户端或服务器向对端发送的请求或响应数据太大时,TCP/IP协议栈控制机制自动将其拆分为若干独立数据报文发送的状况,后面为简化讨论,都以IP分片这个分支为表明,相关过程分析和结论概括对两者均适用)。而一旦一个数据报文发生了IP分片,便会在数据链路层引入屡次的传输和确认,加上报文的拆分和拼接开销,令得整个数据包的发送时延大大增长,而且,IP分片机制中,任何一个分片出现丢失时还会带来整个IP数据报文从最初的发起端重传的消耗。有点枯燥了,更深刻的理解,请参见:《海量之道系列文章之弱联网优化 (二)》。
咱们能够得出以下结论,TCP/IP数据报文大小超过物理网络层的限制时,会引起IP分片,从而增长时空开销。
所以,设定合理的MSS相当重要,对于以太网MSS值建议是1400字节。什么,你的数学是体育老师教的吗?前面说以太网最大的传输数据大小是1500字节,IP数据报文包头是20字节,TCP报文包头是20字节,算出来MSS怎么也得是1460字节呀。若是回答是由于不少路由设备好比CISCO路由器把MSS设定为1400字节,大伙确定不干,回忆一下IP和TCP的数据报包头都各有40字节的可选项,MTU中还须要为这些可选项留出空间,也就压缩了MSS的空间。要是再追问为啥这个值不是1380字节,那就有点过度了。
知识加油站:什么是MSS?
TCP MSS(TCP Maximum Segment Size,TCP最大报文段长度,后面均简称MSS)表示TCP/IP协议栈一次能够传往另外一端的最大TCP数据长度,注意这个长度是指TCP报文中的有效“数据”(即应用层发出的业务数据)部分,它不包括TCP报文包头部分,咱们能够把它理解为卡车能装运生猪的最大数量或重量。它是TCP选项中最常常出现,也是最先出现的选项,占4字节空间。
MSS是在创建TCP连接的三次握手过程当中协商的,每一方都会在SYN或SYN/ACK数据报文中通告其指望接收数据报文的MSS(MSS也只能出如今SYN或SYN/ACK数据报中),说是协商,其实也没太多回旋的余地,缘由一会讲。若是协商过程当中一方不接受另外一方的MSS值,则TCP/IP协议栈会选择使用默认值:536字节。
那么问题来了,控制“限高”哪一种方案才最强。咱们尝试探讨一下。
首先,能够在咱们本身IDC内将各类路由交换设备的MSS设定小于或等于1400字节,并积极参与TCP三次握手时的MSS协商过程,指望达到自动控制服务器收发数据报文大小不超过路径最小MTU从而避免IP分片。这个方案的问题是若是路由路径上其它设备不积极参与协商活动,而它的MTU(或MSS设置值)又比较low,那就白干了。这就比如国家制定了一个高速沿途隧道限高公示通告标准,可是某些地方政府就是不告诉你,没辙。
其次,能够在业务服务中控制应用数据请求/响应的大小在1400字节如下(注:也没法根本避免前述方案中间路由MTU/MSS low的问题),在应用层数据写入时就避免往返数据包大小超过协商肯定的MSS。可是,归根到底,在出发前就把数据拆分为多个数据报文,同IP分片机制本质是相同的,交互响应开销增长是必然的。考虑到人在江湖,安全第一,本方案从源头上控制,显得更实际一些。
固然,最靠谱的仍是作简法,控制传输数据的欲望,用曼妙的身姿腾挪有致,相关的内容放到轻往复章节探讨。
对应到前面的快乐运猪案例,就是要么在生猪装车以前我们按照这条路上的最低限高来装车(问题是怎么能知道整个路上的最低限高是多少),要么按照国家标准规定容许的最小限高来装车,到这里,肥猪们终于能够愉快的上路了,风和日丽,通行无阻,嗯,真的吗?
② 放大TCP拥塞窗口
把TCP拥塞窗口(cwnd)初始值设为10,这也是目前Linux Kernel中TCP/IP协议栈的缺省值。放大TCP拥塞窗口是一项有理有据的重要优化措施,对移动网络尤为重要,咱们一样从一些基本理论开始逐步深刻理解它。
TCP是个传输控制协议,体现控制的两个关键机制分别是基于滑动窗口的端到端之间的流量控制和基于RTT/RTO测算的端到网络之间的拥塞控制。
流量控制目标是为了不数据发送太快对端应用层处理不过来形成SOCKET缓存溢出,就像一次发了N车肥猪,买家那边来不及处理,而后临时囤货的猪圈又已客满,只好拒收/抛弃,相关概念和细节咱们不展开了,有兴趣能够研读《TCP/IP详解 卷一:协议》。
拥塞控制目标是在拥塞发生时能及时发现并经过减小数据报文进入网络的速率和数量,达到防止网络拥塞的目的,这种机制能够确保网络大部分时间是可用的。拥塞控制的前提在于能发现有网络拥塞的迹象,TCP/IP协议栈的算法是经过分组丢失来判断网络上某处可能有拥塞状况发生,评判的具体指标为分组发送超时和收到对端对某个分组的重复ACK。在有线网络时代,丢包发生确实能比较肯定的代表网络中某个交换设备故障或由于网络端口流量过大,路由设备转发处理不及时形成本地缓存溢出而丢弃数据报文,但在移动网络中,丢包的状况就变得很是复杂,其它因素影响和干扰形成丢包的几率远远大于中间路由交换设备的故障或过载。好比短期的信号干扰、进入一个信号屏蔽的区域、从空闲基站切换到繁忙基站或者移动网络类型切换等等。网络中增长了这么多不肯定的影响因素,这在TCP拥塞控制算法最初设计时,是没法预见的,同时,咱们也确信将来会有更完善的解决方案。这是题外话,若有兴趣能够找些资料深刻研究(详见:《TCP/IP详解 - 第21章·TCP的超时与重传》、《通俗易懂-深刻理解TCP协议(下):RTT、滑动窗口、拥塞处理》、《海量之道系列文章之弱联网优化 (三)》)。
拥塞控制是TCP/IP协议栈最经典的和最复杂的设计之一,互联网自我牺牲的利他精神表露无遗,设计者认为,在拥塞发生时,咱们应该减小数据报文进入网络的速率和数量,主动让出道路,令网络能尽快调整恢复至正常水平。
③ 调大SOCKET读写缓冲区
把SOCKET的读缓冲区(亦可称为发送缓冲区)和写缓冲区(亦可称为接收缓冲区)大小设置为64KB。在Linux平台上,能够经过 setsockopt 函数设置SO_RCVBUF和SO_SNDBUF选项来分别调整SOCKET读缓冲区和写缓冲区的大小。
这两个缓冲区跟咱们的TCP/IP协议栈到底有怎么样的关联呢。咱们回忆一下TCP数据报格式及首部中的各字段里面有个16位窗口大小(见下图),还有咱们前面提到的流量控制机制和滑动窗口的概念,大幕徐徐拉开,主角纷纷粉墨登场。在正式详细介绍以前,按照传统,咱们仍是先站在猪场老板的角度看一下,读缓冲区就比如买家用来囤货的临时猪圈,若是货到了买家使用部门来不及处理,就先在这里临时囤着,写缓冲区就比如养猪场根据订单装好车准备发货,若是买家说我如今能够收货即可速度发出,有点明白了吧。
<ignore_js_op>
④ 调大RTO(Retransmission TimeOut)初始值
将RTO(Retransmission TimeOut)初始值设为3s。
TCP为每个报文段都设定了一个定时器,称为重传定时器(RTO),当RTO超时且该报文段尚未收到接收端的ACK确认,此时TCP就会对该报文段进行重传。当TCP链路发生超时时,意味着极可能某个报文段在网络路由路径的某处丢失了,也所以判断此时网络出现拥塞的可能性变得很大,TCP会积极反应,立刻启动拥塞控制机制。
RTO初始值设为3s,这也是目前Linux Kernel版本中TCP/IP协议栈的缺省值,在链路传输过程当中,TCP协议栈会根据RTT动态从新计算RTO,以适应当前网络的情况。有不少的网络调优方案建议把这个值尽可能调小,可是,咱们开篇介绍移动网络的特色之一是高时延,这也意味着在一个RTT比较大的网络上传输数据时,若是RTO初始值太小,极可能发生没必要要的重传,而且还会由于这个事件引发TCP协议栈的过激反应,大炮一响,拥塞控制闪亮登场。
猪场老板的态度是什么样的呢:曾经有一份按时发货的合同摆在个人面前,我没有去注意,等到从新发了货才追悔莫及,尘世间最痛苦的事莫过于此,若是上天能给我一个再来一次的机会,我但愿对甲方说耐心点,若是非要给这个耐心加一个期限的话,我但愿是一万年。
⑤ 禁用TCP快速回收
TCP快速回收是一种连接资源快速回收和重用的机制,当TCP连接进入到TIME_WAIT状态时,一般须要等待2MSL的时长,可是一旦启用TCP快速回收,则只需等待一个重传时间(RTO)后就可以快速的释放这个连接,以被从新使用。
Linux Kernel的TCP/IP协议栈提供了一组控制参数用于配置TCP端口的快速回收重用,当把它们的值设置为1时表示启用该选项:
以上参数中tw是TIME_WAIT的缩写,TIME_WAIT与TCP层的连接关闭状态机相关。具体TIME_WAIT是谁,从哪里来,往哪里去,能够详见:《海量之道系列文章之弱联网优化 (四)》。
⑥ HTTP协议:打开SOCKET的TCP_NODELAY选项
TCP/IP协议栈为了提高传输效率,避免大量小的数据报文在网络中流窜形成拥塞,设计了一套相互协同的机制,那就是Nagle's Algorithm和TCP Delayed Acknoledgement。
Nagle算法(Nagle's Algorithm)是以发明人John Nagle的名字来命名。John Nagle在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896),该问题的具体描述是:若是咱们的应用程序一次产生1个字节的数据(典型的如telnet、XWindows等应用),而这个1个字节数据又以网络数据包的形式发送到远端服务器,那么就很容易使网络中有太多微小分组而致使过载。
由于传输1个字节有效数据的微小分组却需花费40个字节的额外开销(即IP包头20字节 + TCP包头20字节),这种有效载荷利用率极其低下的状况被统称为愚蠢窗口症候群(Silly Window Syndrome),前面咱们在谈MSS时也提到过,若是为一头猪开个大卡车跑一趟,也够愚钝的。对于轻负载广域网或者局域网来讲,尚可接受,可是对于重负载的广域网而言,就极有可能引发网络拥塞致使瘫痪。
现代TCP/IP 协议栈默认几乎都启用了这两个功能。
咱们在移动APP的设计实现中,请求大部分都很轻(数据大小不超过MSS),为了不上述分析的问题,建议开启SOCKET的TCP_NODELAY选项,同时,咱们在编程时对写数据尤为要注意,一个有效指令作到一次完整写入(后面会讲协议合并,是多个指令一次完整写入的设计思想),这样服务器会立刻有响应数据返回,顺便也就捎上ACK了。
① 就快接入
在客户端接入服务器调度策略的演化过程当中,咱们最先采用了“就近接入”的策略,在距离客户端更近的地方部署服务器或使用CDN,指望经过减小RTT来提升网络交互响应性能。这个策略在国内的落地执行还须要加一个前缀:“分省分运营商”,这就给广大负责IDC建设的同窗带来了巨大的精神和肉体折磨。
在持续运营的过程当中,根据观察到的数据,发现并不是物理距离最近的就是最快的。回忆一下前面谈到的吞吐量指标BDP,它与链路带宽和RTT成正比关系,而RTT是受物理距离、网络拥塞程度、IDC吞吐量、跨网时延等诸多因素综合影响的,单纯的就近显然不够精细了。
“就快接入”在“就近接入”策略的基础上改善提高,它利用客户端测速和报告机制,经过后台大数据分析,造成与客户端接入IP按就快原则匹配接入服务器的经验调度策略库,令客户端总能优先选择到最快的服务器接入点。
有关就快接入的更详细方案,请参见:《海量之道系列文章之弱联网优化(五)》一文的“3.1.2节”。
② 去DNS的IP直连
DNS不但须要1个RTT的时间消耗,并且移动网络下的DNS还存在不少其它问题:
综上就是在前述就快接入小节中,接入调度FSM会优先使用动态服务器列表的缘由。
③ 网络可达性探测
在链接创建过程当中若是出现链接失败的现象,而终端系统提供的网络状态接口反馈网络可用时,咱们须要作网络可达性探测(即向预埋的URL或者IP地址发起链接尝试),以区别网络异常和接入服务异常的状况,为定位问题,优化后台接入调度作数据支持。
探测数据能够异步报告到服务器,至少应该包含如下字段:
链路就是运肥猪的高速路,就快接入是选路,链路管理就是如何高效的使用这条路。下面是一些实践总结:
① 链路复用
咱们在开篇讨论无线网络为何慢的时候,提到了连接创建时三次握手的成本,在无线网络高时延、频抖动、窄带宽的环境下,用户使用趋于碎片化、高频度,且请求响应又一次性往返居多、较频繁发起等特征,建链成本显得尤为显著。
所以,咱们建议在链路建立后能够保持一段时间,好比HTTP短连接能够经过HTTP Keep-Alive,私有协议能够经过心跳等方式来保持链路。
具体要点建议以下:
② 区分网络类型的超时管理
在不一样的网络类型时,咱们的链路超时管理要作精细化的区别对待。链路管理中共有三类超时,分别是链接超时、IO超时和任务超时。
咱们有一些经验建议,提出来共同探讨:
超时时间宜短不宜长,在一个合理的时间内令当前链路因超时失效,从而驱动调度FSM状态的快速变迁,效率要比痴痴的等待高得多,同时,在用户侧也能获得一个较好的正反馈。
各种超时参数最好能作到云端可配可控。
③ 优质网络下的并发链路
当咱们在4G、WIFI(要区分是WIFI路由器仍是手机热点)等网络条件较优时,对于请求队列积压任务较多或者有重数据(富媒体等下载类数据)请求时,能够考虑并发多个链路并行执行。
对于单一重数据任务的多连接并发协同而言,须要服务器支持断点续传,客户端支持任务协同调度;
④ 轻重链路分离
轻重链路分离,也能够说是信令和数据分离,目的是隔离网络通信的过程,避免重数据通信延迟而阻塞了轻数据的交互。在用户角度看来就是信息在异步加载,控制指令响应反馈及时。
移动端大部分都是HTTP短连接模式工做,轻重数据的目标URL自己就不一样,比较自然的能够达到分离的要求,可是仍是要特别作出强调,是由于实践中有些轻数据协议设计里面还会携带相似头像、验证码等的实体数据。
⑤ 长连接
长连接对于提高应用网络交互的及时性大有裨益,一方面用户使用时,节省了三次握手的时间等待,响应快捷;另外一方面服务器具有了实时推送能力,不但能够及时提示用户重要信息,并且能经过推拉结合的异步方案,更好的提高用户体验。
长连接的维护包括连接管理、连接超时管理、任务队列管理等部分,设计实施复杂度相对高一些,尤为是在移动网络环境下。为了保持链路还须要作心跳机制(从另一个角度看,这也是针对简单信息一个不错的PULL/PUSH时机,,但需注意数据传输要够轻,好比控制在0.5KB之内),而心跳机制是引入长连接方案复杂度的一个重要方面,移动网络链路环境复杂,国内网关五花八门,链路超时配置各有千秋,心跳时长选择学问比较大,不但要区分网络类型,还得区分不一样运营商甚至不一样省市,历史上曾经实践了2分钟的心跳间隔,最近比较多的产品实践选择4.5分钟的心跳间隔。并且长连接除了给移动网络尤为是空中信道带来负担外,移动设备自身的电量和流量也会有较大的消耗,同时还带来后端带宽和服务器投入增长。
因此,除了一些粘性和活跃度很高、对信息到达实时性要求很高的通信类APP外,建议谨慎使用长连接,或能够考虑采用下面的方式:
有关Android的推送问题,能够参考:
《应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)》
《Android进程保活详解:一篇文章解决你的全部疑问》
《Android端消息推送总结:实现原理、心跳保活、遇到的问题等》
《深刻的聊聊Android消息推送这件小事》
《为什么基于TCP协议的移动端IM仍然须要心跳保活机制?》
《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》
《移动端IM实践:实现Android版微信的智能心跳机制》
《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》)
⑥ 当心重试
自动重试是致使后台雪崩的重要因素之一。在移动网络不稳定的条件下,大量及时的重试不但不能达到预期,反而无谓的消耗移动设备的电量甚至流量。
所以,咱们在重试前要有一些差别化的考虑:
每一个目标服务器地址的重试次数、重试总时限和重试时间间隔最好能作到云端可配可控。
特别须要提出的一点是,移动APP采用HTTP短连接模式实现CS交互时,普遍的使用了系统原生组件或者开源组件,这些友好的模块把超时和重试都封装起来,其缺省值是否适合本身的业务特色,须要多多关注。使用前,最好能知其然更知其因此然。
⑦ 及时反馈
透明和尊重,会带来信任和默契,家庭如此、团队如此、用户亦如此。此地无银三百两和装傻充愣也许短暂取巧,拉长时间轴来看,确定要付出惨重的代价。及时和真诚的告知情况,赢得谅解和信任,小付出,大回报,试过都知道。
当发现由于网络不存在或者其它属于移动端设备链路的异常时,应该及时和显著的提示用户,让用户注意到当前有诸如网络不存在、FREE WIFI接入认证页面需确认等等问题,使用户能够及时处理或理解问题状态。
当发现是服务器问题时,应及时、显著和真诚的告知用户,争取用户的谅解。
网络异常提示或服务器故障通告等信息的呈现要作到一目了然,无二义和二次交互。
基于一个快速和高效管理的链路之上,作好IO调度和控制,也是提高效能和改善用户体验的重要环节。
要探讨的内容包括:
① 异步IO
异步化IO的目的就是避免资源的集中竞争,致使关键任务响应缓慢。咱们在后面差别服务个大的分类中会重点探讨。这里特别先提出来,是建议在程序架构顶层设计时,要在总体机制上支持异步化,设计必要的异步总线来联系各个层级模块,总线可能会涉及包括队列管理(优先级、超时、CRUD等)、事件驱动、任务调度等。
异步IO除了网络方面外,对移动设备,咱们还特别要考虑一下磁盘IO的异步。由于频繁、大吞吐量的磁盘IO会形成APP的UI卡顿,从用户体验上看就是交互响应迟钝或者滑动帧率降低。通常来讲,磁盘IO异步会选用空间换时间的方案,即缓存数据批量定时写入磁盘。
② 并发控制
有了异步IO,并发控制就显得尤其重要。把异步机制看成银弹任意使用,就如同咱们给移动APP设计了一个叫“发现”的地方同样,极可能各类膨胀的需求、不知道如何归类的需求就纷至沓来,期待有朝一日被“发现”。
异步IO提供了一个很好的发射后不用管的机制,这就会形成使用者的膨胀,不管是否必要、不管轻重缓急,把请求一股脑的丢给异步队列,本身潇洒的转身就走。这样不但会带来效率和交互响应性能的降低,也会形成资源的无谓消耗。
在后面多异步这个大分类的讨论中会涉及到轻重缓急的话题,在前述异步IO的磁盘IO的时空效率转换话题中,还应该包括IO并发的控制,咱们即不能由于并发过多的链路形成网络带宽的独占消耗影响其它APP的使用,也不可因快速、大量的异步数据形成缓写机制形同虚设或是占用过大的内存资源。
③ 推拉结合
PUSH机制应该是苹果公司在移动设备上取得辉煌成就的最重要两个机制之一,另一个是移动支付体系。咱们这里的讨论不包括iOS和APPLE移动设备的拟人化交互体验,只侧重根基性的机制能力。APNS解决了信息找人的问题,在过去,只有运营商的短信有这个能力,推送和拉取使得咱们具有了实时获取重要信息的能力。
为什么要推拉结合。由于系统级的推送体系也必须维持一个本身的链路,而这个链路上要承载五花八门的APP推送数据,若是过重,一方面会在设计上陷入个性化需求的繁琐细节中,另一方面也会形成这条链路的拥堵和性能延迟。所以,经过PUSH通知APP,再由APP经过本身的链路去PULL数据,即有效的利用了PUSH机制,又能使得APP能按需使用网络,不但简化了链路管理,并且节省了电量和流量。
④ 断点续传
一方面,在讨论链路管理时,咱们建议了优质网络下的并发链路来完成同一个重数据拉取任务。这就会涉及到任务的拆分和并行执行,基础是后台能支持断点续传。
另一方面,从客户端的角度而言,移动网络的不稳定特色,可能会形成某个重数据拉取任务忽然失败,不管是自动重试仍是用户驱动的重试,若是能从上次失效的上下文继续任务,会有省时间、省电量和省流量的效果,想一想也会以为十分美好。
“技”止此尔。强调网络交互的“少”,更应强调网络交互的“简”。
咱们在一条高时延易抖动的通道上取得效率优点的关键因素就是减小在其上的往复交互,最好是老死不相往来(过激),而且这些往复中交换的数据要尽可能的简洁、轻巧,轻车简从。这个概念是否是有点像多干多错,少干少错,不干没错。
把咱们实践过的主要手段提出来探讨:
① 协议二进制化
二进制比较紧凑,可是可读性差,也所以造成可维护性和可扩展性差、调测不便的不良印象。这也形成了大量可见字符集协议的出现。计算机是0和1的世界,她们是程序猿的水和电,任何一个整不明白,就无法愉快的生活了。
② 高效协议
高效的协议能够从两个层面去理解,一是应用层标准协议框架,二是基于其上封装的业务层协议框架,有时候也能够根据须要直接在TCP之上把这两个层面合并,造成纯粹的业务层私有协议框架。不过,为了简化网络模块的通信机制和一些通用性、兼容性考虑,目前大多数状况下,咱们都会选择基于HTTP这个应用层标准协议框架之上承载业务层协议框架。下面咱们针对上述两个层面展开探讨。
首先是应用层的标准协议优化:好比HTTP/1.1的Pipeline、WebSocket(在HTML5中增长)、SPDY(由Google提出)、HTTP/2等,其中特别须要关注的是处在试验阶段的SPDY和草案阶段的HTTP/2。
SPDY是Google为了规避HTTP/1.1暨之前版本的局限性开展的试验性研究,主要包括如下四点:
HTTP/2由标准化组织来制定,是基于SPDY的试验成果开展的HTTP协议升级标准化工做,有兴趣了解详细状况能够参考HTTP/2的DRAFT文档。
其次是业务层的协议框架优化:它能够从三个方面考察
可能会有同窗强调协议调测时的可阅读、可理解,既然读懂01世界应该是程序员的基本修养,这一项可能就没那么重要了。
高效的业务层协议框架从分布式系统早期表明Corba的年代就有不少不错的实践项目,目前最流行的开源组件应属ProtoBuf,能够学习借鉴。
正所谓异曲同工、心有灵犀、不谋而合,英雄所见略同......,说来讲去,高效协议的优化思路也都在链路复用、推拉结合、协议精简、包压缩等等奇技淫巧的范畴以内。
有关Protobuf等技术的详细文章,请参见:
《Protobuf通讯协议详解:代码演示、详细原理介绍等》
《如何选择即时通信应用的数据传输格式》
《强列建议将Protobuf做为你的即时通信应用数据传输格式》
《全方位评测:Protobuf性能到底有没有比JSON快5倍?》
《移动端IM开发须要面对的技术问题(含通讯协议选择)》
《简述移动端IM开发的那些坑:架构设计、通讯协议和客户端》
《理论联系实际:一套典型的IM通讯协议设计详解》
《58到家实时消息系统的协议设计等技术实践分享》
《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》
《金蝶随手记团队分享:还在用JSON? Protobuf让数据传输更省更快(原理篇)》
《金蝶随手记团队分享:还在用JSON? Protobuf让数据传输更省更快(实战篇)》
③ 协议精简
协议精简的目的就是减小无谓的数据传输,提高网络效能。俗话说“千里不捎针”,古人诚不我欺也。
咱们实践总结如下三点供参考:
④ 协议合并
协议合并的目标是经过将多条交互指令归并在一个网络请求中,减小链路建立和数据往复,提高网络效能。
把实战总结的六点提出来供参考:
⑤ 增量技术
增量技术准确分类应该算是协议精简的一个部分,它与业务特色结合的很是紧密,值得单独讨论一下。增量技术在CS数据流交互比较大的时候有充分发挥的空间,由于这个技术会带来客户端和服务器计算、存储的架构复杂度,增长资源消耗,而且带来许多保障数据一致性的挑战,固然,咱们能够设计的更轻巧,允许一些不一致。
咱们用一个案例来看看增量技术的运用。
在应用分发市场产品中,都有一个重要功能,叫更新提醒。它的实现原理很简单,以Android设备为例,客户端把用户移动设备上安装的APP包名、APP名称、APP签名、APP版本号等信息发送到服务器,服务器根据这些信息在APP库中查找相应APP是否有更新并推送到客户端。这个过程很是简单,但若是用户手机上装了50个APP,网络上交互的数据流就很是客观了,即浪费流量和电量,又形成用户体验的缓慢,显得很笨重。
这个时候,增量技术就能够派上用场了,好比下面的方案:
⑥ 包压缩
前面精打细算完毕,终于轮到压缩算法上场了。选择什么算法,中间有哪些实战的总结,下面提出来一块儿探讨:
说到这,问题又来了,若是应用层标准协议框架作了压缩,那么基于其上封装的业务层协议框架还须要压缩吗,压缩技术到底哪家强?这个问题真很差回答,考虑到HTTP/2这样的应用层标准协议框架定稿和普及尚需时日,建议在业务层协议框架中作压缩机制。或者追求完美,根据后端应用层标准协议框架响应是否支持压缩及在支持时的压缩算法如何等信息,动态安排,总的原则就是一个字:只选对的,不选贵的。
可监方可控,咱们在端云之间,要造成良好的关键运营数据的采集、汇总和分析机制,更须要设计云端可控的配置和指令下发机制。
本篇重点讨论与主题网络方面相关关键指标的“监”和“控”。
以就快接入为例来探讨一下强监控能力的构建和使用:
经过数据分析,结合服务器自身的监控机制,能够作到:
特别须要注意的是,客户端数据报告必定要有数据筛选控制和信息过滤机制,涉及用户隐私的敏感信息和使用记录必须杜绝采样上报。在咱们的日志染色机制中要特别注意,为了排查问题很可能把关键、敏感信息记录报告到后端,引入安全风险。
通过前面不懈的努力,初步打造了一个比较好的技术根基,好马配好鞍,好车配风帆,怎么就把领先优点拱手送与特斯拉了。
用户欲壑难平,资源供不该求,靠“术”并没有法优雅的解决。跳出来从产品角度去观察,还有些什么可以触动咱们思考的深度呢。根据不一样的需求和使用场景,用有损服务的价值观去权衡取舍,用完美的精神追求不完美,此乃道的层面。
所谓大道至简,完美之道,不在无可添加,而在无可删减。经过多异步和各种缓存机制,提供区分网络、区分业务场景下的差别化服务,是咱们孜孜以求的大“道”。
下面经过一些实践案例的总结,来探索简洁优雅的弱联网体验改善之道(开始肆无忌惮的吹嘘了)。
① 网络交互能否延后
微博客户端某个版本启动时,从闪屏加载到timeline界面须要6秒+。这样的体验是没法接受的,与用户2秒之内的等待容忍度是背道而驰的。从技术角度去分析,很容易发现问题,诸如咱们在启动时有10+个并发的网络请求(由于是HTTP短连接,意味着10+个并发的网络连接)、闪屏加载、主UI建立、本地配置加载、本地持久化数据加载至Cache等等程序行为,优化的目标很天然就集中在网络请求和本地配置、持久化数据加载上。
梳理并发网络请求,能够从如下三个方面考察:
此时,取舍就很是简单和清晰了,启动时1~2个网络请求足够应对。所作的仅仅是把一些请求延后发起,这是一种异步机制。
在移动APP里面还有大量相似的场景,好比用户更新了APP的某个设置项或者本身Profile的某个字段,是停在界面上转菊花等网络交互返回后再提示结果,亦或是把界面交互立刻还给用户,延后异步向服务器提交用户请求,这里面的价值取向不一样,“快”感也便不一样。
② 网络内容能否预先加载
微博客户端在timeline刷新时,用户向上快速滑屏,到达一个逻辑分页(好比30条微博消息)时,有两个取舍,一是提早预加载下个分页内容并自动拼接,给用户无缝滑动的体验;二是等到用户滑动到达分页临界点时现场转菊花,卡不卡看当时的网络情况。实践中选择了方案一。用户在滑动浏览第一个逻辑分页时,APP就利用这个时间窗主动预先拉取下一个逻辑分页的内容,使得用户能享受一个顺畅的“刷”的体验。
所作的仅仅是把一个请求提早发起了,这也是一种异步机制。思考的要点是:
在移动APP中,预加载有大量的实践,比较典型的就是升级提醒,你们都采用了先下载好升级包,再提示用户有新版本的策略,让你顺畅到底。
③ 用户体验能否降级
微博客户端在香港公共WIFI下刷新timeline老是失败,经过后台用户接入请求和响应日志分析,判断是香港IDC到香港公共WIFI的汇接口带宽窄、时延大,此时该如何应对。
从前面探讨的TCP/IP网络知识,能够知道,在一个窄带宽高时延网络中,吞吐量BDP必然很小,也就是说单位大小的数据传输所需的时间会很长。若是按照一般一次下发一个逻辑分页timeline数据的策略,那么从服务器到客户端传输,整个数据须要拆分红多个TCP数据报文,在缓慢的传输过程当中,可能一个数据报文还未传输完成,客户端的链路就已经超时了。
若是在弱网络(须要在应用层有测速机制,相似TCP/IP的RTT机制,测速时机能够是拉取微博消息数字时)下,把逻辑分页的微博消息数由30调整为5会如何,若是方案成立,用户刷微博的体验是否是会降低,由于滑动一屏就要作一次网络交互,即使是配合预加载,也可能由于网络太慢,操控太快而又见菊花。外团在香港实测了这个版本,感叹,终于能够刷了。
在饥渴难耐和美酒佳肴之间,彷佛还有不少不一样层级的体验。聊胜于无,这个词很精准的表述了服务分层,降级取舍的重要性。思考的要点是:
在移动弱网络条件下,到处可见降级取舍的案例。好比网络条件不佳时,下降拉取缩略图的规格,甚至干脆不自动拉取缩略图等等,分层由心,降级有意。
④ 端和云孰轻孰重
移动APP时代,绝对的轻端重云或者轻云重端都是不可取的,只有端云有机的配合,才能在一个受限的网络通道上作出更好的用户体验。正所谓东家之子,胖瘦有致。
好比移动网游APP,如取向选择轻端重云,那么玩家的战斗计算就会大量的经过网络递交给服务器处理并返回,卡顿屡见不鲜,操控感尽失。
好比微博客户端,若是取向选择重端轻云,微博timeline全部的消息都拉取元数据(好比微博正文包括文字、各种URL、话题、标签、@、消息的父子关系、消息中用户profile、关系链等等),由客户端实时计算拼装,不但客户端用户须要消耗大量流量计算量,并且给后端服务器带来巨大的带宽成本和计算压力,若是过程当中网络情况不佳,还会很是卡顿。
经过实践总结,端和云孰轻孰重,取舍的关键是在数据计算规模可控和数据安全有保障的前提下:
端云有机结合,能够很好的演绎机制与策略分离的设计思想,从而使系统具有足够的柔韧性。
不得再也不次特别提到的一点是,缓存技术是异步化的基础,它渗透在性能和体验提高的方方面面,从持久化的DB、文件,到短周期的内存数据结构,从业务逻辑数据,到TCP/IP协议栈,它无所不在。缓存涉及到数据结构组织和算法效能(耗时、命中率、内存使用率等)、持久化和启动加载、更新、淘汰、清理方案等,有机会咱们能够展开作专题的介绍。牢记一个字,缓存是让用户爽到极致的利器,但千万别留下垃圾。
提倡多异步,其实是要求团队认真审视产品的核心能力是什么,深刻思考和发现什么是用户最关心的核心体验,把有限的资源聚焦在它们身上。经过考察用户使用产品时的心理模型,体验和还原用户使用场景,用追求完美的精神探索不完美之道。
互联网服务核心价值观之一“不要我等”,在移动互联网时代仍应奉为圭臬,如何面对新的挑战,须要更多的学习、思考、实践和总结,这篇文章便是对过去实践的总结,亦做为面对将来挑战的思考基点。
老子曰过:上士闻道,勤而行之;中士闻道,若存若亡;下士闻道,大笑之。不笑不足觉得道。求求你了,笑一个。
知易行难,故知行合一似(jiu)为扯蛋,那么咱们就且扯且珍惜吧。
(上篇看了吗?没看请戳这里:《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》)
《TCP/IP详解 - 第11章·UDP:用户数据报协议》
《TCP/IP详解 - 第17章·TCP:传输控制协议》
《TCP/IP详解 - 第18章·TCP链接的创建与终止》
《TCP/IP详解 - 第21章·TCP的超时与重传》
《技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)》
《通俗易懂-深刻理解TCP协议(上):理论基础》
《通俗易懂-深刻理解TCP协议(下):RTT、滑动窗口、拥塞处理》
《理论经典:TCP协议的3次握手与4次挥手过程详解》
《理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程》
《计算机网络通信协议关系图(中文珍藏版)》
《UDP中一个包的大小最大能多大?》
《P2P技术详解(一):NAT详解——详细原理、P2P简介》
《P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解》
《P2P技术详解(三):P2P技术之STUN、TURN、ICE详解》
《通俗易懂:快速理解P2P技术中的NAT穿透原理》
《高性能网络编程(一):单台服务器并发TCP链接数到底能够有多少》
《高性能网络编程(二):上一个10年,著名的C10K并发链接问题》
《高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了》
《高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索》
《鲜为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)》
《鲜为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)》
《鲜为人知的网络编程(三):关闭TCP链接时为何会TIME_WAIT、CLOSE_WAIT》
《鲜为人知的网络编程(四):深刻研究分析TCP的异常关闭》
《鲜为人知的网络编程(五):UDP的链接性和负载均衡》
《鲜为人知的网络编程(六):深刻地理解UDP协议并用好它》
《鲜为人知的网络编程(七):如何让不可靠的UDP变的可靠?》
《网络编程懒人入门(一):快速理解网络通讯协议(上篇)》
《网络编程懒人入门(二):快速理解网络通讯协议(下篇)》
《网络编程懒人入门(三):快速理解TCP协议一篇就够》
《网络编程懒人入门(四):快速理解TCP和UDP的差别》
《网络编程懒人入门(五):快速理解为何说UDP有时比TCP更有优点》
《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》
《让互联网更快:新一代QUIC协议在腾讯的技术实践分享》
《现代移动端网络短链接的优化手段总结:请求速度、弱网适应、安全保障》
《聊聊iOS中网络编程长链接的那些事》
《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》
《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》
>> 更多同类文章 ……
(本文同步发布于:http://www.52im.net/thread-1588-1-1.html)