本文原始内容由爱奇艺技术产品团队原创分享,本次有修订和改动。
1、引言
由于移动网络的复杂性特点,编写高质量、体验好的具备网络通信能力的移动端应用(尤其是即时通讯这类网络质量高度敏感的应用)有很大的挑战性。
我们平时看到的移动网络主要有如下三个典型特点:
1)移动状态网络信号不稳定,高时延、易抖动丢包、通道狭窄;
2)移动状态网络接入类型和接入点变化频繁;
3)移动状态用户使用高频化、碎片化、非WIFI流量敏感。
(▲ 上述文字,引用自《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》)
正是由于上述特点,移动端应用在进行网络数据通信时会面临各种复杂多变的问题。
无论后面的技术有多复杂,但对于普通用户使用APP来说,能顺畅的完成网络请求,是理所当然的事。换句话说,APP网络请求成功率,重要性直接体现在它能直接决定APP服务的可用性,直接影响到数据通信、视频播放、广告展现、支付便捷等服务质量。
本文将以爱奇艺的iOS端APP为例,分享对移动网络请求成功率优化方面的技术实践之路。
本文将同时发布于“即时通讯技术圈”公众号,欢迎关注:
(本文已同步发布于:http://www.52im.net/thread-2981-1-1.html)
2、相关文章
《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》
《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》(* 必读好文)
《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》
《全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等》
《美图App的移动端DNS优化实践:HTTPS请求耗时减小近半》
《百度APP移动端网络深度优化实践分享(一):DNS优化篇》
《百度APP移动端网络深度优化实践分享(二):网络连接优化篇》
《百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇》
3、导致移动端网络请求失败的因素
想要优化移动端网络请求成功率,先来了解移动端网络请求全链条可能导致请求失败的环节有哪些。
这些环节往往由以下两类因素导致:
第一类:不可改善因素:
1)iOS系统对APP的网络访问权限控制、飞行模式或者无网络连接。检测和识别这三种情况,通过适当方式提示用户;
2)路由器故障。
第二类:可以改善因素:
1)蜂窝/Wifi信号的强弱、连接拥堵的假连接状态;
2)DNS故障(比如DNS劫持等);
3)运营商局部节点故障;
4)自有运营负载均衡故障;
5)业务服务器故障:HTTP响应错误,对应APM的HTTP响应错误率;
6)业务逻辑错误:监控子类解析结果,对应APM的解析错误率监控。
对于不可改善因素:目前只能通过网络诊断识别出故障类型,引导用户手动去授权访问网络或者连接可用网络。
其中,如果是路由器故障,可以引导用户重启路由器或者切换4G。通过爱奇艺APP的数据监控,大致可以看到用户无网连接的时长占比有3.8%左右,这说明提供好的无网提示变得十分重要,而从用户使用蜂窝信号的弱信号(0格和1格信号)时长占比有9%左右时长,也可以看出移动端网络环境的复杂性。
针对可以改善的因素,解决方法可大致分为三类:
1)网络层错误,对应因素1到4。主要体现为超时报错;
2)HTTP响应错误,对应因素5。HTTP状态码为400及以上;
3)解析错误,对应因素6。由基线网络库定义的重载接口进行监控。
为了提高网络请求成功率,首先需要建立监控体系,从而使得基线网络库能够通过网络统计模块向APM投递各种维度的网络请求数据。有了APM的数据统计后,才能有效的发现导致端上网络失败的原因,进而解决问题。
除此之外,由于端上网络请求数据巨大,存储空间的限制使得APM只能采样2%的用户,因此针对重点业务的网络请求(比如首页)则进行了全量采集,从而对成功率的优化实现更客观全面的评估。
4、在基线网络库这一层针对不同业务提供不同的补偿思路
在优化之前,通过APM的归类分析可以得出:请求失败的主要报错是超时(-1001)的占比达到九成,与此同时SSL错误,DNS解析错误占比紧随其后。根据这一数据统计,重试成为最主要的请求成功率优化的措施。
经过不断探索和实践总结,基线网络库针对不同业务需求提供了四种不同的重试手段。
1)IP直连重试,通过配置直连IP数来控制重试次数:
Scheme不变,Host改为直接使用IP(消除域名解析风险)。由于此举需要各个业务线自己提供直连的IP,目前接入的业务主要是登录等强制要求HTTPS连接的业务。
2)超级管道重试,可以配置1~3次重试:
公司自研基于HTTP的网关代理服务(类似于远程charles代理)。Host改为代理IP(消除域名解析风险),Scheme改为HTTP(消除SSL风险,h2降级为HTTP1.1)。由于该措施需要付出流量成本,目前接入的业务都是关键核心业务,比如首页等。
3)HTTP重试,可以配置1~3次重试:
Scheme修改为HTTP(消除SSL风险,h2降级为HTTP1.1),其他不变。鉴于其为普惠性重试手段,目前接入非关键核心的一般业务。
4)原url重试,可以配置1~3次重试:
Scheme和host等都不变,通常意义上理解的重试,单纯的再请求一次。此举目前不是推荐重试手段,由业务方自主决定。
除了单个重试手段可以重试多次,基础网络库也支持多种重试手段的组合,四种重试手段的优先次序为:IP直连重试 > 超级管道重试 > HTTP重试 > 原URL重试。扣除无网情况,首页推荐页CARD接口成功率通过组合重试在2020第一季度末达到了99.76%。
5、其它影响移动端网络请求成功率的因素
除了重试,还有以下因素对网络请求成功率有直接影响。
1)HTTP/2 vs HTTP/1.1:推荐的请求策略是首次请求走H2,当失败重试时走HTTP/1.1:
HTTP/2对HTTP/1.1最大改进是共用一个TCP连接(详见《从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路》),其在网络顺畅时,为HTTP/2带来了速度上的优势。但当网络变坏时,TCP包的绝对顺序编号会导致一个包的丢失而堵住后面所有的请求。这样单TCP连接反而扩大了拥堵,增大了请求失败的可能性。
NSURLSession是HTTP协议自适应的,不能控制请求使用HTTP/2或者HTTP/1.1。不过由于业界事实上的标准要求HTTP/2必须是HTTPs的,这样通过将URL Scheme改为HTTP可以间接降级到HTTP/1.1。
2)适当的超时设置是一个重要影响因素:
NSURLSession的超时实际上是TCP的包间超时,并不是整体请求耗时的超时。
推荐的超时设置策略是:首次请求的超时可以小一点,而重试的超时应该大一些。
3)接口请求过于密集并发可能降低请求成功率:
比如播放记录的upload接口在加上多次重试后,成功率仍然只有98.2%。APM监控此接口在IPv4环境失败率只有0.47%,而IPv6失败率高达7.07%。通过端上优化请求策略,降低接口的并发密度后,IPv6环境和IPv4环境同时提高到99.85%的成功率。
4)接口数据体积越小,请求成功率越高:
HTTP/2和HTTP/1.1都是基于TCP连接的,接口数据体积越小,需要传输的TCP包越少,传输失败的概率也就降低了。目前爱奇艺APP正在从gzip转向压缩率更高的br(指的是Brotli压缩算法,详见:《启用 Brotli 压缩算法,对比 Gzip 压缩 CDN 流量再减少 20%》)。
6、提高鲁棒性并防止故障的优化措施
在经过各种优化措施提高网络成功率后,我们还通过下面几个措施成功的防止线上故障造成的成功率瞬时下降,提高了网络请求的鲁棒性。
1)超级管道本身的鲁棒性:
下面案例显示使用了超级管道重试的接口错误率只有3.95%,而没有使用超级管道重试的接口错误率高达28.96%。这个案例的时间点还没有使用异地容灾IP,在叠加异地容灾IP之后,错误率曲线几乎可以抹平。
2)HTTP重试和原URL重试在v4v6双栈环境下,优先IPv4:
由于IPv6仍在建设中,有些接口在IPv6的表现弱于IPv4,那么可以指定重试走IPv4。
3)TLS1.3– 1RTT的节省:
TLS1.3将SSL握手2个RTT降为1个RTT,降低了SSL握手失败的概率。iOS12.2开始,NSURLSession支持TLS1.3。只需要服务器升级支持TLS1.3即可,端上无须改动。
4)IP复合连接竞速:
使用TCP连接测速,目的是剔除坏IP,选择最优IP,从而提高请求的成功概率。
经上述措施的持续优化,爱奇艺APP在2020Q1末,扣除无网情况后,业务成功率达到了99.7%,而网络层成功率达到了99.77%。
▲ 业务成功率 = 网络层成功率+HTTP响应成功率+解析成功率
在完成优化后,爱奇艺APP基础网络库的构成如下:
如上图所示,基础网络库各模板的功能作用如下:
1)统一网络库:提供一个网络接口层,所有业务接口都对接使用网络接口层;
2)统一网络库:提供一个网络封装层,对接了iOS系统网络层NSURLSession、ASIHTTPRequest(基于CFNetwork)、和公司自研的长连接网关;
3)网络统计模块:将从业务调用开始到回调给业务方的各个环节的耗时及状态值,变成统计数据,上传到APM汇合;
4)网络诊断模块:对关键业务进行诊断,包括dns解析,ping,tcpconnect,trace等工具对具体IP进行分析,分析结果上传到APM汇合;
5)弱网检测模块:通过借鉴Facebook的弱网检测是基于网速拟合的网络等级分级,分为网络情况非常差(2G或者无网)、网络情况较差(3G)、网络情况一般、网络情况较好、网络情况非常好五个等级;
6)HTTPDNS模块:有效的解决了运营商劫持问题;
7)超级管道重试:基于HTTP的网关代理,具有异地容灾代理能力;
8)ipv4/ipv6模块:识别端上是ipv4 only环境、v4/v6双栈还是ipv6 only环境;
9)复合连接模块:可以在server IP缓存池选出最佳IP,手段包括目标IP连接竞速,IP历史请求统计数据排序;
10)网络日志模块:记录了最近发生的失败网络请求详细数据和网络诊断数据。随反馈一并提交,可以便捷的排查线上网络问题。
7、未来的目标与可能的优化措施
为了持续优化网络成功率,下一步目标是扣除无网情况,重点业务成功率达到99.9%。后续考虑的优化措施如下。
1)Multipath:
当Wifi假连接的时可以走蜂窝流量,iOS 7开始支持Multipath特性(详见:《揭开 iOS 7 之 Multipath TCP 的面纱》)。
2)QUIC:
QUIC是基于UDP的,由于运营商对UDP有针对性的丢包,实测QUIC并没有体现出优势。然而,考虑到libcurl在2019已提供完整QUIC能力,NSURLSession不久也会支持QUIC。随着运营商对UDP包的干扰减少,QUIC的优势将得到体现。
如果对QUIC协议感兴趣,可以读一读下面这些文章:
《网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议》
《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》
《让互联网更快:新一代QUIC协议在腾讯的技术实践分享》
《七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!》
3)智能调度并发:
更精准更灵敏的弱网识别,弱网下对关键核心业务进行倾斜。
4)HTTPDNS的push能力:
HTTPDNS打通APM的质量监控体系后,通过push及时下线故障IP。
关于移动端DNS问题上的优化,业内已经有了很多总结,有兴趣可以深入研究:
《全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等》
《美图App的移动端DNS优化实践:HTTPS请求耗时减小近半》
《百度APP移动端网络深度优化实践分享(一):DNS优化篇》
《移动端网络优化之HTTP请求的DNS优化》
附录:更多网络通信方面的技术资料
《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中的NAT穿越(打洞)方案详解(进阶分析篇)》
《P2P技术详解(四):P2P技术之STUN、TURN、ICE详解》
《通俗易懂:快速理解P2P技术中的NAT穿透原理》
《高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少》
《高性能网络编程(二):上一个10年,著名的C10K并发连接问题》
《高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了》
《高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索》
《高性能网络编程(五):一文读懂高性能网络编程中的I/O模型》
《高性能网络编程(六):一文读懂高性能网络编程中的线程模型》
《Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!》
《不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)》
《不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)》
《不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT》
《不为人知的网络编程(四):深入研究分析TCP的异常关闭》
《不为人知的网络编程(五):UDP的连接性和负载均衡》
《不为人知的网络编程(六):深入地理解UDP协议并用好它》
《不为人知的网络编程(七):如何让不可靠的UDP变的可靠?》
《不为人知的网络编程(八):从数据传输层深度解密HTTP》
《不为人知的网络编程(九):理论联系实际,全方位深入理解DNS》
《网络编程懒人入门(一):快速理解网络通信协议(上篇)》
《网络编程懒人入门(二):快速理解网络通信协议(下篇)》
《网络编程懒人入门(三):快速理解TCP协议一篇就够》
《网络编程懒人入门(四):快速理解TCP和UDP的差异》
《网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势》
《网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门》
《网络编程懒人入门(七):深入浅出,全面理解HTTP协议》
《网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接》
《网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?》
《网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议》
《网络编程懒人入门(十一):一文读懂什么是IPv6》
《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》
《让互联网更快:新一代QUIC协议在腾讯的技术实践分享》
《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》
《聊聊iOS中网络编程长连接的那些事》
《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》
《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》
《IPv6技术详解:基本概念、应用现状、技术实践(上篇)》
《IPv6技术详解:基本概念、应用现状、技术实践(下篇)》
《从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路》
《脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手》
《脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?》
《脑残式网络编程入门(三):HTTP协议必知必会的一些知识》
《脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)》
《脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?》
《脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?》
《脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解》
《脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?》
《以网游服务端的网络接入层设计为例,理解实时通信的技术挑战》
《迈向高阶:优秀Android程序员必知必会的网络基础》
《全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等》
《美图App的移动端DNS优化实践:HTTPS请求耗时减小近半》
《Android程序员必知必会的网络通信传输层协议——UDP和TCP》
《IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)》
《IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)》
《IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁》
《IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史》
《IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史》
《IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术》
《IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”》
《IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲》
《IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”》
《IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲》
《IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!》
《IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!》
《IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!》
《IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!》
《IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够》
《百度APP移动端网络深度优化实践分享(一):DNS优化篇》
《百度APP移动端网络深度优化实践分享(二):网络连接优化篇》
《百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇》
《技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结》
《可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?》
《知乎技术分享:知乎千万级并发的高性能长连接网关技术实践》
《5G时代已经到来,TCP/IP老矣,尚能饭否?》
《爱奇艺移动网络优化实践分享:网络请求成功率优化篇(iOS端)》
>> 更多同类文章 ……
欢迎关注我的“即时通讯技术圈”公众号:
(本文已同步发布于:http://www.52im.net/thread-2981-1-1.html)