WWDC Quick Look 💓 By SwiftGGTeam
Reduce networking delays for a more responsive app

Reduce networking delays for a more responsive app

观看原视频

Highlight

Apple 将 app 响应性拆成往返时长和往返次数两个因素,并给出 HTTP/3、QUIC 迁移、QUIC datagrams、服务器缓冲区调优和 L4S 兼容性测试这些可落地的降延迟方法。


核心内容

很多网络问题看起来像带宽不足。视频会议卡顿、屏幕共享延迟、视频跳转后长时间 rebuffer,用户第一反应往往是升级宽带。Session 一开始就给出反例:带宽从 1Mbps 提到 2Mbps 时,页面加载时间下降接近 40%;超过 4Mbps 后,继续增加带宽几乎不再改善页面加载时间。相反,延迟每下降 20 毫秒,页面加载时间会线性改善(03:24)。

真正拖慢 app 的,是每一次 round trip 的时长,以及完成一次请求需要多少个 round trip。队列通常堆在网络里最慢的链路上,新包必须排在旧包后面。TLS 1.2 over TCP 取得第一个响应包可能需要 4 次往返;当每次往返都被队列放大,首包时间就会变得很长(02:16)。

Apple 给出的路线分三层:app 侧减少往返次数,服务器侧减少无意义排队,网络侧测试 L4S。app 只要使用 URLSession 和 Network.framework,在服务器开启后就能自动使用 IPv6、TLS 1.3 和 HTTP/3;如果使用 QUIC,还可以启用连接迁移和 datagram flow(04:45)。

服务器同样会制造延迟。Session 用 WWDC 视频随机跳转作为例子:服务器 TCP、TLS、HTTP 缓冲区分别配置到 4MB、256KB、4MB,新生成的数据包被排在旧数据后面,导致视频跳转后长时间黑屏。把 HTTP、TLS、TCP 缓冲区降到 256KB、16KB、128KB 后,再次跳转可以立即恢复播放(09:36)。

详细内容

采用 HTTP/3 并启用连接迁移

06:03)移动设备经常从 Wi-Fi 切到蜂窝网络。普通连接需要重新建立,app 会短暂停顿。HTTP/3 基于 QUIC,支持连接迁移。对于 URLSession,Session 给出的 opt-in 方式很短:

let configuration = URLSessionConfiguration.default
configuration.multipathServiceType = .handover

关键点:

  • URLSessionConfiguration.default 创建默认会话配置,后续请求可以继续走系统网络栈。
  • multipathServiceType = .handover 允许连接在网络切换时迁移,目标是减少 Wi-Fi 到蜂窝切换时的 stall。
  • 服务器需要支持 HTTP/3;app 侧使用 URLSession 后,协议选择由系统在可用时处理。

如果你直接使用 Network.framework 创建 QUIC 连接,同一能力配置在 NWParameters 上:

let parameters = NWParameters.quic(alpn: ["myproto"])
parameters.multipathServiceType = .handover

关键点:

  • NWParameters.quic(alpn:) 创建 QUIC 参数,alpn 用来声明应用层协议名称。
  • multipathServiceType = .handover 开启 handover 模式,让连接在网络变化时尽量保持连续。
  • Session 建议启用后用自己的 app 验证,因为连接迁移需要和实际协议、服务器部署一起测试。

用 QUIC datagrams 替代直接使用 UDP

06:39)如果自定义协议直接使用 UDP,iOS 16 和 macOS Ventura 提供了 QUIC datagrams。它们保留 datagram 的使用方式,同时会响应网络拥塞,帮助维持较低 round-trip time,并减少丢包。

// Only one datagram flow can be created per connection
let options = NWProtocolQUIC.Options()
options.isDatagram = true
options.maxDatagramFrameSize = 65535

关键点:

  • 注释说明每个连接只能创建一个 datagram flow,这会影响协议设计。
  • NWProtocolQUIC.Options() 创建 QUIC 协议选项。
  • options.isDatagram = true 声明该 QUIC flow 使用 datagram 模式。
  • options.maxDatagramFrameSize = 65535 设置允许的最大 datagram frame 大小。
  • 创建 datagram flow 后,可以像普通 QUIC stream 一样发送和接收数据。

用 networkQuality 找出服务器排队

07:49)macOS Monterey 引入的 network quality tool 可以测服务商网络,也可以测你自己的服务器。做法是先把服务器配置成测试目的端,然后分别测 Apple 默认服务器和自有服务器。如果默认服务器得分好,自有服务器得分差,问题很可能在服务端排队。

networkQuality -s -C https://myserver.example.com/config

关键点:

  • networkQuality 是 macOS 的网络质量测试工具。
  • -s 让工具按服务器测试模式运行。
  • -C https://myserver.example.com/config 指向你的测试服务器配置。
  • Session 建议用默认服务器和自有服务器各跑一次,比较响应性得分。

Apple 还列出了可用于外部验证的三个测试入口:

https://www.waveform.com/tools/bufferbloat
https://github.com/network-quality/goresponsiveness
https://www.speedtest.net/

关键点:

  • Waveform 提供 Bufferbloat test,用来观察排队导致的延迟。
  • goresponsiveness 是 responsiveness test 的 Go 开源实现。
  • Ookla Speedtest app 增加了 responsiveness measurement,并展示 round-trip time。

调小服务器缓冲区

09:36)Session 的视频跳转案例里,服务器缓冲区太大。新数据被旧数据挡住,用户看到的是 rebuffer。Apple 在 Apache Traffic Server 中降低 TCP、TLS、HTTP/2 的缓冲行为:

% cat /opt/ats/etc/trafficserver/records.config

# Set not-sent low-water mark trigger threshold to 128 kilobytes
CONFIG proxy.config.net.sock_notsent_lowat INT 131072

# Set Socket Options flag to the sum of the options we want
# TCP_NODELAY(1) + TCP_FASTOPEN(8) + TCP_NOTSENT_LOWAT(64) = 73
CONFIG proxy.config.net.sock_option_flag_in INT 73

...

# Enable Dynamic TLS record sizes
CONFIG proxy.config.ssl.max_record_size INT -1

...

# Reduce low-water mark and buffer block size for HTTP/2
CONFIG proxy.config.http2.default_buffer_water_mark INT  32768
CONFIG proxy.config.http2.write_buffer_block_size   INT 262144

关键点:

  • proxy.config.net.sock_notsent_lowat 把 TCP not-sent low-water mark 设为 128KB。
  • sock_option_flag_in 组合启用 TCP_NODELAYTCP_FASTOPENTCP_NOTSENT_LOWAT
  • proxy.config.ssl.max_record_size INT -1 启用动态 TLS record sizes。
  • proxy.config.http2.default_buffer_water_mark 降低 HTTP/2 low-water mark。
  • proxy.config.http2.write_buffer_block_size 调整 HTTP/2 写缓冲块大小。
  • 如果使用其他 web server,需要寻找等价配置,而不是照搬 ATS 配置名。

测试 L4S 兼容性

14:50)L4S 是 Apple 与网络社区合作推进的低延迟技术,在 iOS 16 和 macOS Ventura 中以 beta 形式提供。它通过显式拥塞信号让发送端调整速率,目标是保持短队列并实现 zero congestion loss。

在 macOS Ventura 上,可以用 Session 给出的 defaults 命令开启测试:

defaults write -g network_enable_l4s -bool true

关键点:

  • defaults write -g 写入全局偏好设置。
  • network_enable_l4s 是 macOS Ventura 中用于开启 L4S beta 测试的开关。
  • -bool true 将该开关设为开启。
  • iOS 16 中对应入口在 Developer settings。
  • 如果用 Linux server 测试 QUIC,QUIC 实现需要支持 accurate ECN 和 scalable congestion control algorithm。

核心启发

  • 为视频或直播服务增加服务器响应性巡检:把 networkQuality -s -C 接入上线前检查。先测 Apple 默认服务器,再测自有服务器。两者差距大时,优先检查 TCP、TLS、HTTP 缓冲区。

  • 给实时协作 app 增加网络切换测试用例:在 Wi-Fi 和蜂窝之间切换,观察正在进行的请求或 QUIC 连接是否 stall。URLSessionConfiguration.multipathServiceType = .handover 是最小入口。

  • 把自定义 UDP 协议迁移到 QUIC datagrams 试验分支:保留 datagram 数据模型,用 NWProtocolQUIC.Options 开启 datagram flow,再验证拥塞场景下的 round-trip time 和丢包变化。

  • 为屏幕共享或远程控制 app 建立 L4S 兼容测试:在 iOS 16 Developer settings 或 macOS Ventura defaults 开启 L4S,跑真实交互流程,记录菜单响应、光标移动和画面更新时间差。

  • 把 RPM 当成网络体验指标:Ookla 展示 round trip time 后,可以用 60000 / RTT(ms) 得到 round trips per minute。这个指标比单纯下载速度更贴近视频会议、屏幕共享和搜索建议的体验。

关联 Session

评论

GitHub Issues · utterances