8、网络优化:HTTP/2与QUIC实践、DNS预解析与连接池、弱网环境下的自适应码率

网络优化,说白了就是跟延迟和丢包作斗争。我做了这么多年音视频,最深的体会就是:网络不好,再好的编解码也白搭。今天咱们就聊聊传输层那些事儿——从HTTP/2到QUIC,从DNS到连接池,再到弱网下的自适应码率策略。

8.1 HTTP/2:多路复用才是王道

先说说HTTP/2。我记得刚接手一个直播项目时,发现首屏加载要3秒多。查了半天,问题出在HTTP/1.1的队头阻塞上——一个请求卡住,后面全得等着。

HTTP/2的核心改进就两点:

  • 二进制分帧:不再是文本协议,解析效率高得多
  • 多路复用:一个TCP连接可以同时发多个请求

但注意,HTTP/2也有坑。它虽然解决了应用层的队头阻塞,但TCP层的队头阻塞依然存在。什么意思?就是一个TCP包丢了,后续所有流都得等它重传。这在弱网环境下特别致命。

实践建议:如果你的App主要跑在WiFi或4G稳定的环境下,HTTP/2够用了。但如果是移动端弱网场景,建议直接上QUIC。

8.2 QUIC:Google的杀手锏

QUIC是什么?说白了就是基于UDP的“TCP 2.0”。它把HTTP/2的流概念和TLS加密都搬到了UDP上,彻底解决了队头阻塞问题。

我个人习惯在音视频传输中优先考虑QUIC,原因有三:

  1. 0-RTT建连:之前连过的服务器,第二次握手直接发数据
  2. 无队头阻塞:一个流丢包不影响其他流
  3. 连接迁移:从WiFi切到4G,连接不断

我曾经在一个跨国直播项目中,用QUIC替换了TCP,首屏加载时间从2.8秒降到了0.9秒。嗯,这个提升还是很明显的。

小技巧:Android端集成QUIC可以用Cronet库,它是Chromium的网络栈,支持QUIC和HTTP/2。记得开启enable_quic选项。

8.3 DNS预解析:别让DNS成为瓶颈

你想想看,用户点开视频,先要DNS解析域名,这一步可能就要几百毫秒。如果DNS服务器响应慢,或者被劫持,体验直接崩了。

我的做法是:在App启动时就预解析常用域名。Android上可以用NetworkService或者OkHttp的DNS接口。

// OkHttp自定义DNS预解析
val dns = Dns { hostname ->
    val cached = dnsCache[hostname]
    if (cached != null) {
        cached
    } else {
        val result = Dns.SYSTEM.lookup(hostname)
        dnsCache[hostname] = result
        result
    }
}

val client = OkHttpClient.Builder()
    .dns(dns)
    .build()

另外,我建议在用户点击播放按钮之前,就把视频CDN的域名解析好。这样用户真正播放时,DNS已经完成了。

避坑指南:我曾经遇到过DNS缓存过期导致解析到旧IP的问题。解决方案是设置合理的TTL,并在网络切换时主动刷新DNS缓存。

8.4 连接池:复用才是硬道理

每次建TCP连接都要三次握手,加上TLS握手,耗时至少一两百毫秒。连接池就是为了避免重复建连。

OkHttp默认就有连接池,但默认配置不一定适合音视频场景。我一般会调大maxIdleConnectionskeepAliveDuration

val connectionPool = ConnectionPool(
    maxIdleConnections = 10,      // 默认5
    keepAliveDuration = 10,       // 默认5分钟
    TimeUnit.MINUTES
)

val client = OkHttpClient.Builder()
    .connectionPool(connectionPool)
    .build()

但注意,连接池不是越大越好。连接太多会占用系统资源,反而影响性能。我一般根据并发请求数来调,比如同时播放3路视频,就设5-6个空闲连接。

8.5 弱网环境下的自适应码率

这是音视频网络优化的核心。说白了就是:网络好时播高清,网络差时播流畅

自适应码率(ABR)的常见策略有:

策略 原理 适用场景
基于吞吐量 根据下载速度选码率 带宽波动不大的场景
基于缓冲区 根据播放器缓冲区水位选码率 直播场景
混合策略 结合吞吐量和缓冲区 通用场景

我个人习惯用混合策略。具体做法是:

  1. 每2秒测量一次下载吞吐量
  2. 同时监控播放器缓冲区剩余时长
  3. 如果缓冲区低于3秒,立即降码率
  4. 如果吞吐量持续高于当前码率的1.5倍,尝试升码率

核心原则:降码率要快,升码率要慢。避免频繁切换导致用户体验差。

我曾经在一个弱网优化项目中,把切换码率的阈值从1.2倍调到了1.5倍,卡顿率从12%降到了5%。为什么?因为频繁切换码率本身就会导致播放中断,留点余量反而更稳。

8.6 整体架构图

下面这张图展示了网络优化的整体流程:

Android音视频网络优化架构 DNS预解析 App启动时预解析 连接池复用 减少TCP/TLS握手 协议选择 HTTP/2 vs QUIC 传输层优化 多路复用 · 0-RTT · 连接迁移 自适应码率(ABR) 吞吐量测量 · 缓冲区监控 · 码率切换策略 流畅播放 · 低延迟

8.7 总结

网络优化没有银弹。HTTP/2适合稳定网络,QUIC适合弱网环境。DNS预解析和连接池是基础优化,必须做。自适应码率是音视频的杀手锏,降码率要果断,升码率要谨慎。

嗯,最后说一句:别迷信某个技术,多在实际网络环境下测试。我见过太多项目在办公室WiFi下跑得飞起,一到用户手里就卡成PPT。网络优化,最终还是要看用户的实际体验。

推荐工具:用Facebook的Network Connection Class库来检测网络质量,或者自己写一个基于ping延迟和丢包率的检测器。数据说话,比感觉靠谱。

公众号:蓝海资料掘金营,微信deep3321