ChenYilong / iOS11AdaptationTips

for iOS11 in [ObjC, Swift, English, 中文] {...} -- iOS11适配系列教程
MIT License
486 stars 47 forks source link

iOS11开发新特性之网络部分 #24

Open ChenYilong opened 6 years ago

ChenYilong commented 6 years ago

iOS11开发新特性之网络部分

前言

网络优化技术进阶 为了给用户提供更好的用户体验,在网络优化和新技术使用方面,苹果一直都保持著很积极的态度,近两年也多次通过加强审核的方式大力推广 IPv6 和 https;每年的 WWDC 都有若干网络优化的 session,介绍和讨论新的网络技术和使用情况;

今年的 Advances in Networking 进一步分享了 ECN/IPV6/MPTCP 等几项技术带来的收益,以及苹果网络相关 API 的一些新特性;

主要内容:

ECN

首先所有的网络协议都是为了最大化的使用网络资源,一直到网络出现拥塞; 出现拥塞时会导致丢包,而 TCP 默认的处理是对丢包进行重传;这种方法代价非常大,发送方持续重试可能导致耗电,设备的网络资源也会被无端占用,而网络也可能更加拥塞,需要很长时间才能恢复; 有效的优化拥塞和避免拥塞将减少重传,减少延迟,并极大提升用户体验;

重发为何会带来非常大的性能损耗:原因是因为 TCP 的慢启动与初始拥塞窗口(initial congestion window, initcwnd)。

好的传输协议必须最大限度地利用带宽,而 TCP 有启动速度限制,也就是初始拥塞窗口(initial congestion window, initcwnd),随着时间与稳定性的增加,才能最大限度地使用带宽。一旦发生拥塞重连,将带来非常大的性能损耗。重连时将采用初始拥塞窗口,这个值是连接中最慢的,窗口的限制也会拖慢整个传输过程:在拥塞窗口设置的较小时,对于 TLS 连接,TLS 握手消息消耗了宝贵的初始连接字节(当拥塞窗口较小时),如果拥塞窗口足够大,那么慢启动不会有额外的延迟。但是如果较长的握手消息超过了拥塞窗口的大小,发送方将必须把它拆分成两块,先发送一块儿,等待确认(一个往返),增加拥塞窗口,然后再发送剩下的部分。这也加剧了

扩展说明:

TCP 内置的拥塞控制(congestion control)机制,在一个新的连接开始时,你不知道对端有多快。如果有足够的带宽,你可以用最快的速度传送数据,但如果你正在处理一个缓慢的移动网络连接呢?如果发送的数据太多,你会压垮连接,导致连接中断。出于这个原因,每一个 TCP 连接都有一个拥塞窗口(congestion window)的速度极限。这个窗口的初始值非常小,在可靠性能保证的情况下随时间增长,这种机制被称为慢启动(slow start)。

这带来了反直觉的现象:所有的 TCP 连接,启动速度很慢,随着时间的推移速度增加,直到它们充分发挥其潜力。这对于 HTTP 连接而言,往往是坏消息;它们几乎总是在不理想的条件下工作。重发同理。

综上拥塞是 TCP 的性能瓶颈,TCP 设计之初检测拥塞的方式,只能在发生了丢包时才会发现发生了拥塞。仅从丢包来识别拥塞,代价过高。

优化的思路有两种:

前者有 quick 之类的协议替换 TCP 协议,Apple 也在积极开发中,iOS11暂时未支持。后者则是基于 TCP 做一些扩展、完善,ECN 就是一种,ECN 已经在 iOS 中全面支持。

什么是 ECN ?

全称:Advantages of Explicit Congestion Notification(显式拥塞通知),当网络拥塞发生时,因为发送方无法及时知晓网络情况,在发现丢包时会不断的重发,导致网络情况更加糟糕,而 ECN 的出现就解决了这个问题,ECN 是 TCP IP 协议的扩展,其实现是在 ip header 中加入 1 bit 的拥塞状态值,由接收方回传给发送方;发送方收到这个消息时既停止发送数据包,直到拥塞解除;

ECN 需要客户端、服务端和网络三方面的支持,但是得益于 ECN 隶属 Linux 内核,所以只需要运营商升级 Linux 即可支持,APPLE 给出了 Server 对 ECN 支持率:

数据:

时间 2013 2017
Server 对 ECN 支持率 35% 74%

客户端方面,iOS 10.3 开始,50% 的通过 Wifi 和少量通过移动网络进行的 TCP 连结已经打开了 ECN,没有收到相关问题的报告; 通过也收集到了一些国家出现网络拥塞的情况:

地区 网络拥塞情况
美国 0.2%
中国 1%
法国 5%、
阿根廷 30%

综上,客户端从 iOS 11 开始,所有 TCP 请求都会支持 ECN(全部Wifi 和部分白名单移动运营商);服务端有 74% 的网站支持了 ECN,也会有越来越多的网络服务商开始支持 ECN 来进一步提升用户体验;(服务商只需要在你的网络接入点支持 ECN 即可);

显式标记连接拥塞,更加高效。

在使用 ECN 的同时,需要结合使用 SQM (Smart Queue Management) 算法 来进行数据缓存,他会保证是真正的拥塞出现前告知发送者当前的网络这块,最大程度上的避免拥塞出现;

ECN 的实现细节

ECN 是 TCP IP 协议的扩展,其实现是在 ip header 中加入 1 bit 的拥塞状态值,由接收方回传给发送方;发送方收到这个消息时既停止发送数据包,直到拥塞解除;

ECN flag 的位置,在 IPv4 中对应于 ToS ,IPv6对应于 Traffic Class。

enter image description here

更详细的位置:

enter image description here

参考链接:

15 年的 session 中 有一个实验对比图:没有 ECN 时 在传输初段出现了明显的网络拥塞,而且持续了很久才恢复正常;而在使用了 ECN + CoDel 算法优化后,没有出现明显的数据终端和因拥塞导致的丢包和重传;

Reference:

your app and next generation networks wwdc/2015/719

IPv6

IPv6 相比 IPv4, IPv6 有更大的地址空间,更小的路由表,更高安全性等优势。

World IPv6 Launch 始于 2016 年 6 月 6 日,包括中国在内的若干国家开始启用 IPv6(事实上中国进展缓慢)。支持 IPv6 的设备从 5 年前的不到 1% 提升到今天的接近 20%。欧美大多数的移动运营商也已同时支持 IPv6 和 IPv4。经过策略改进,HTTPS 请求在 IPv6 下提升了 15%-30%。

15 年的 session 里已经提到了 NAT64,如果服务端只支持 IPv4, 在 IPv6 环境下,可以通过 NAT64 DNS64 技术去正常访问。

16 年 6 月起,苹果也开始要求所有 App 提交时必须经过 NAT64 测试,支持 IPv6 网络;现在因为 IPv6 被拒的 App 已经很少了。

Networking stack changes 网络协议分层

Networking stack changes 传统的网络分层模型中,接口层和传输层 TCP/IP 都在内核态;剩下的协议处理在用户态;数据在这两者间传输时需要做一些上下文切换。

意义在于,

数据在这两者间传输时避免了一些上下文切换,效率更高。

可以预见,将来在 NSURLSession 中将开放更多的用于调整 TCP 传输的接口,让我们继续期待后续更新吧。

MutliPath TCP

Multipath protocols for Multipath Devices(适合多链路设备的多链路 TC P协议)

增加了对使用多个接口(如Wi-Fi和Cellular)的支持,通过扩展 URLSessionConfiguration 以支持 IETF、RFC 6824中定义的多路径TCP传输单个数据流。有关更多信息,请参阅URLSessionConfiguration.MultipathServiceType。

阶段 iOS10.3 iOS 11
客户端 50% 100%

不要使用 BSD 的 Socket,不要嵌入其他网络类库,优先使用 APPLE 的网络类库,底层网络通信在 CPU、内存、电量使用已经做了很多优化,在数据传输效率、动态链接通道切换都有优化,使用其他网络库,无法享受优化成果。

NEDNSProxyProvider

NEDNSProxyProvider feature in iOS11

向网络扩展框架添加了新的 DNS 代理应用程序扩展类型。

Receives the system’s DNS query messages Handles them as it wishes

Can send to recursive resolver of its choice Can send using protocol of its choice

支持:

仅仅适用于 VPN 类 APP

DNS Proxy provider: also for non-managed devices?

Reference:

WKWebView Cookie 管理

基本在这里面展示了他的特性 参考:《iOS 防 DNS 污染方案调研(四)--- Cookie 业务场景》

URLSession Adaptable Connectivity API

重大更新!现在可以通过 urlSession(_:taskIsWaitingForConnectivity:) 让请求等待网络正常后再自动尝试。

URLSessionTask Scheduling API

通过 URLSessionTask Scheduling API 可以在 App 没有运行的时候下载内容,而手机也会结合实际电量,使用状态去决定是否执行。

ziyilixin commented 6 years ago

👍

Muscliy commented 6 years ago

👍

sunyazhou13 commented 6 years ago

URLSessionTask Scheduling API 可以在 App 没有运行的时候下载内容 这个实现应该是啥样的呢 进程交给 操作系统了 还是 操作系统对这段 api 特殊处理了

ChenYilong commented 6 years ago

Apple没透露实现细节,但理论上和你描述上的应该是一致的。

jiangchao829 commented 6 years ago

11.3 断点续传失败 可否有了解?

junqingwuchu commented 6 years ago

ECN? 了解一下