WWDC 2021 - 为你的 App 减少网络延迟

| iOS , WWDC

 

内容概览

  • 前言
  • 网络延迟如何影响你的应用
    • Developer - Responsiveness(RPM)
  • 采用最新的网络请求API
    • HTTP/3 & QUIC
    • TCP Fast Open
      • 幂等性
    • TLS 1.3
    • Multipath TCP
  • 将应用内的网络流量情况告知系统
  • 总结

 

前言

 

如今,很多App都会在加载数据的时候显示一个加载指示器(旋转菊花?)。然而,有些App经常会处于加载状态,而且加载的时间很长。如果您遇到这种App,您会选择怎么解决这种问题呢?

  • 换一个更快的网络?
  • 反馈问题,期待App团队进行改进?
  • 找到这个App的替代品,卸载这个App?

我猜,大多数人都会选择最后一个选项。如何避免咱们的App因为网络延迟太久而被用户抛弃,无疑是我们这些App开发人员要面对的一个问题。

别怕,苹果工程师给大家带来了灵丹妙药!来,和 Ficow 一起瞧瞧吧~

 

网络延迟如何影响你的应用

 

比起上传、下载吞吐量和闲置状态的 ping 值,影响应用网络延迟的主要因素是工作状况下的网络响应。

常见的网络测速都是测量闲置情况下的网络延迟,而更重要的其实是应用在被使用的过程中的网络连接质量。

iOS 15 中的开发者设置提供了网络响应调试菜单:

点击 Test 之后,你会看到一个提示框(告知你,这个操作会产生网络流量):

这个测试需要持续数秒,期间它会测试工作状态下的网络质量。最终它会报告每分钟内网络数据往返的次数(round trips per minute, RPM)。
由于毫秒对于大多数人来说是比较抽象的概念,而且人们更熟悉“越高就越好”的测量结果,所以这里没有采用毫秒度量单位。最终,RPM的测量结果从几百到几千不等。

macOS 上也有其对应的命令行工具:NetworkQuality。

如果你正在使用设备的网络,这个测量结果可能会非常糟糕。当设备闲置(没有使用网络)的时候,网络数据一次往返的时间为 20 毫秒。但是,当设备在处理网络数据的时候,这个时间可能会高达 600 毫秒甚至更多。二者差了30倍至多呢!

 

工作状况下的网络响应情况对于应用的用户体验非常重要。我们经常会遇到音频、视频卡顿的情况,不过,视频会议卡顿的情况会更加明显,毕竟现在很多人在家办公。

当我们遭遇视频会议卡顿的情况后,很多人都会想法设法提高网络带宽,比如从100M升级至300M。然而问题依旧。为什么呢?

因为:当网络缓冲区很大,而且被填满时,缓冲区不但不能提高吞吐量,反而使延迟更长。

 

我们通常会认为网络数据包会很快地通过网络发送出去:

然而,实际上它是这样工作的(缓冲区越大,队伍就越长):

当然,已经有了一些对付 Bufferbloat 的算法。比如,CoDel 算法:

Bufferbloat 是我们的App经常会经历的延迟,除此之外还有软硬件的处理延迟。如今,CPU越来越快,处理的时间也在不断缩短。到最后,就是光信号传递本身的延迟(光纤通信)。

 

常见的延迟因素:处理延迟、传输延迟、缓冲延迟、光信号传递延迟。

网络延迟的问题不会消失。这也是为什么,我们要着重考虑应用内的网络数据 往返的次数

 

众所周知,视频会议、游戏应用受到网络延迟影响最严重。然而,其实各式各样的应用都受到了网络延迟影响,所以我们经常会在各种应用内看到加载指示器转个不停。

经常让用户等待的App,极有可能会被用户抛弃。如果你的应用也显示这种加载指示器,那么接下来的优化方法可以帮你减少用户的等待时间。

其实,应用的响应速度由这个公式决定:1 / (数据请求的往返时间 * 数据请求的往返次数)

然而,作为一个普通开发者,我们很难控制数据请求的往返时间。但是,我们可以减少数据请求的往返次数!

接下来,让我们看一下该怎么做吧~

 

采用最新的网络请求API

 

采用以下新技术,您的应用有可能大幅度地减少网络数据的往返次数:

iOS 和 macOS 都支持这些技术。不过,采用这些技术 还需要服务端的支持

 

HTTP/3 & QUIC

iOS 15 和 macOS Monterey 已经默认支持 HTTP/3 和 QUIC。

QUIC 是一个能比 TCP 和 TLS 更快建立链接的基于UDP的传输协议。通过减少队头阻塞,QUIC 可以显著地减少传输延迟。

只要您使用 URLSession,你就用上了 QUIC。

如果您使用了 Network.framework 中的API,那么也只需要创建一个带有 QUIC 参数和 TLS 支持的 NWConnection 连接对象即可。

具体内容,请参考: Accelerate networking with HTTP/3 and QUIC

 

TCP Fast Open

QUIC 适用于很多场景,然而很多应用依然会使用 TCP。

在使用 TCP 时,您可以在 TCP 握手包中附带一些数据,以此来减少往返次数。 Network.framework 和 Sockets 都支持 TCP Fast Open。

 

在 NWConnections 中使用 TCP Fast Open,有两种选择:

1.配置 allowFastOpen 为 true,然后在发送握手包之前,先添加要发送的初始数据。

请注意,您应该只发送 幂等的请求

 

2.如果您在使用基于 TCP 的 TLS,您也可以选择把 TLS 握手信息作为初始数据:

找到 TCP 相关选项,配置 enableFastOpentrue

推荐使用基于 Network.framework 的方式来使用 TCP Fast Open。不过,如果您的应用基于 Sockets 构建,您可以调用 connectx 方法并传入相关的参数来表明您想在握手时发送幂等数据。

 

幂等性

所谓 幂等性,就是 任意多次执行所产生的影响均与一次执行的影响相同,不会产生副作用。

常见的 GET 请求就是幂等的,在多个服务器之间的调用不会产生副作用:

而购买 iPhone 的 POST 请求,会在多个服务器的调用之间产生副作用,导致各自的结果不同(iPhone的库存变化):

 

TLS 1.3

对比 TLS 1.2,TLS 1.3 移除了握手过程中的一次往返,同时也更安全了。iOS 13.4 中已为 URLSession 和 NWConnection 默认开启了 TLS 1.3。

TLS 1.3 也支持在 TLS 握手消息中加入幂等的初始数据。

 

Multipath TCP

Multipath TCP 减少网络延迟的方式略有不同,它允许一个 TCP 连接在设备切换网络的时候不中断。

为了获得 Multipath TCP 的低延迟特性,您需要为 URLSession 或 NWParameters 的 multipathServiceType 属性开启 interactive 模式。然后,之后,系统会在建立连接时,节省所有往返次数,而且自动为数据包选择最快的网络路径。

 

优化效果

假设您当前的应用采用的是基于 TCP 的 TLS 1.2,获取第一个字节的数据需要 4 次往返:

基于苹果的实测,常见的一次往返时间可以高达 600 毫秒,4 次往返便可高达近 2.5 秒!也就是,用户需要盯着加载指示器 2 秒多!

采用了新式的网络协议之后,这个时间可以被显著地缩短到 0.6 秒:

用户可以很明显地感受到这个优化的效果。如果您想真实环境中的提高网络性能,数据往返次数是一个非常值得注意的参数。

如果要在 macOS 内模拟真实的弱网络条件,您可以去苹果开发者网站下载 Network Link Conditioner 开发者工具。
如果要在iOS真机内模拟,可以在系统设置中的 Developer 菜单内配置。

 

将应用内的网络流量情况告知系统

 

很多应用都有发送和接收的混合流量。

当设备运行多个应用时,多个应用会共享设备的网络,这时可能会出现较长的网络请求队列。

为了避免共享网络出现太长的队列,应用最好对数据进行合理的分类以便系统高效地管理应用的流量。

在 iOS 15 和 macOS Monterey 中,后台服务被显著改善。苹果为后台上传、下载服务添加了新的拥塞控制算法。这些算法不仅显著地减少了网络延迟,还确保完成后台传输的耗时和其他传输任务几乎相同。

让我们来看一下您可以为后台服务采用的网络 API:

当您的App在前台执行一些非用户触发的传输任务时,您可以使用默认的 URLSession,然后将 URLRequest 的网络服务类型配置为 background。这样做可以允许系统保持低网络延迟。对于 NWConnection,可以将 serviceClass 配置为 background

如果您的App需要执行一个长时间运行的传输任务,无论是否是用户触发的,你可以创建一个后台的 URLSession。这样,即使App进程被系统挂起了,这个任务也可以继续运行。

对于具有时效性的任务,您可以将 isDiscretionary 属性设置为 true。这样做可以让系统在等到最佳网络条件时才执行数据传输。

除了网络队列之外,发送设备本身也是导致延迟的一个因素。以前,网络栈使用了非常大的发送缓冲区,而这会导致不必要的延迟。在 2015 年,苹果已经在 URLSession 和 NWConnection 中解决了这个问题。

但是,网络中的很多服务器采用的是 Linux 系统,而且使用了 BSD Sockets。您可以联系您的服务器提供商,确保他们启用了 TCP_NOTSENT_LOWAT 选项以在源头上减少延迟。

 

总结

 

接下来,您可以采用文中提到的新式网络协议来消除多余的往返次数:

  • 为预加载资源、大块的传输数据和不紧急的任务开启 background 模式;
  • 在不同的网络条件下测试 App 的网络性能,建议使用 Network Link Conditioner;

保持较低的网络延迟,可以有效的帮助我们的产品提升整体的用户体验。行动起来吧~

 

参考内容:
Reduce network delays for your app

 

觉得不错?点个赞呗~

本文链接:WWDC 2021 - 为你的 App 减少网络延迟

转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog

评论区(期待你的留言)