减少你的 App 网络延迟
Reduce network delays for your app
2021年6月10日
一句话判断
网络延迟优化的最大收益不在代码层面——启用 HTTP/3、配置 DNS 预解析、复用连接这三招能砍掉 50% 以上的延迟。
这场 Session 讲了什么
Session 从系统层面讲解了如何减少 App 的网络延迟。核心观点是:大部分网络延迟不是你的代码慢,而是协议和连接管理不够优化。
三大优化方向:一是启用 HTTP/3(基于 QUIC 协议)。HTTP/3 在传输层使用 UDP 代替 TCP,消除了 TCP 的队头阻塞问题(Head-of-Line Blocking),在丢包的网络环境下性能提升明显。iOS 15 和 macOS Monterey 的 URLSession 默认支持 HTTP/3,你只需要服务端支持。
二是 DNS 预解析(DNS Prefetching)。在用户可能发起请求之前提前解析域名,省掉首次请求时的 DNS 查询时间。
三是连接复用和资源调度。避免多个请求串行发送,用 HTTP/2 的多路复用或并发请求最大化带宽利用率。
值得深挖的点
HTTP/3 的队头阻塞消除
HTTP/2 解决了 HTTP 层的队头阻塞(一个 TCP 连接上可以并行多个流),但 TCP 层的队头阻塞仍然存在——一个 TCP 包丢了,后面所有的包都得等。HTTP/3 的 QUIC 协议在 UDP 之上实现了独立的流,每个流的丢包只影响自己所在的流,不影响其他流。在移动网络(丢包率 1-3%)环境下,这意味着一个请求的丢包不会拖慢同时进行的其他请求。
DNS 预解析的时机
DNS 解析通常需要 20-200ms(取决于 DNS 服务器的距离)。如果你在用户点击按钮时才开始 DNS 解析,这 200ms 就加到了用户感知的延迟中。iOS 15 允许你通过 NWConnection 的参数配置预解析——在 App 启动时或用户浏览列表时就解析好可能用到的域名。
代码片段
启用 HTTP/3
import Network
// 使用 URLSession 自动支持 HTTP/3
// 只需在服务端配置 Alt-Svc header:
// Alt-Svc: h3=":443"; ma=86400
let config = URLSessionConfiguration.default
// iOS 15 默认支持 HTTP/3,无需额外配置
// 只要服务端 advertise 支持,URLSession 会自动升级
let session = URLSession(configuration: config)
使用 Network 框架进行 DNS 预解析
import Network
// 预解析域名
func prefetchDNS(host: String) {
let endpoint = NWEndpoint.hostPort(
host: NWEndpoint.Host(host),
port: 443
)
let parameters = NWParameters.tcp
let connection = NWConnection(to: endpoint, parameters: parameters)
// 只需要启动连接的解析阶段
connection.stateUpdateHandler = { state in
if case .ready = state {
// DNS 解析完成,连接已建立
connection.cancel()
}
}
connection.start(queue: .global())
}
并发请求最大化带宽利用率
// 错误:串行请求
// func loadAll() async throws {
// let user = try await fetchUser() // 等完成
// let feed = try await fetchFeed() // 再等
// let config = try await fetchConfig() // 再等
// }
// 正确:并发请求
func loadAll() async throws -> (User, [FeedItem], Config) {
// async let 让三个请求同时发出
async let user = fetchUser()
async let feed = fetchFeed()
async let config = fetchConfig()
// 等待所有结果
return try await (user, feed, config)
}
最佳实践
基础设施: 联系你的后端团队启用 HTTP/3(nginx、Cloudflare、AWS ALB 都已支持)。在响应头中添加 Alt-Svc 告知客户端支持 HTTP/3。配置 CDN 的边缘节点离用户更近。
App 层面: 在 App 启动时预解析核心 API 域名。使用 async let 并行化独立的网络请求。避免在 UITableViewCell 的 cellForRowAt 中同步发起请求——提前批量加载。
还有什么值得关注
- iOS 15 的
URLSession在弱网环境下自动重试失败请求。 - NWConnection 的
pathUpdateHandler可以监控网络状态变化,在 Wi-Fi 和蜂窝之间切换时自动调整。 - Instruments 的 Network 工具可以可视化展示 HTTP/3 和 HTTP/2 的性能差异。