
一 、短视背景
我们平时在看抖音快手视频的频用时候,如果滑动到某个视频画面一直几s不动的户访化实时候,大概率就会划走了,问体所以在短视频项目中 ,验优画面卡顿是短视非常影响用户体验的 ,启播速度越快 ,频用就越能留住用户。户访化实
启播速度简单来说就是问体从调用开始播放到首帧上屏的时间 ,大致可分为两部分 :
视频文件下载耗时视频解码耗时本文主要从运维排查问题的验优角度 ,香港云服务器从网络这部分的短视各个环节入手 ,结合vivo短视频的频用具体案例,给大家分享下优化过程。户访化实
二、问体用户访问链路
我们先梳理下一次完整的验优网络请求过程,以客户端视角为例 ,如下图所示:

在接入CDN的情况下,可分为几个阶段 :
DNS域名解析 :获取服务器的IP地址。TCP连接建立:与服务器IP建立连接即tcp三次握手 。TLS握手:客户端向服务器索要并验证服务器的公钥,高防服务器双方协商生产「会话秘钥」并进行加密通信。CDN响应:将内容资源分发到位于多个地理位置机房中的服务器上并返回给客户端 。针对以上阶段,分别讲下vivo短视频是如何进行优化的。
三、DNS域名解析
我们在上网的时候,通常使用的方式域名 ,而不是 IP 地址,因为域名方便人类记忆 。那么实现这一技术的云计算就是 DNS 域名解析,DNS 可以将域名网址自动转换为具体的 IP 地址。
3.1 域名的层级关系DNS 中的域名都是用句点来分隔的,比如 www.server.com ,这里的句点代表了不同层次之间的界限。在域名中 ,越靠右的位置表示其层级越高 。模板下载根域是在最顶层,它的下一层就是 com 顶级域,再下面是 server.com 。
所以域名的层级关系类似一个树状结构 :
根DNS服务器顶级域 DNS 服务器(com)权威 DNS 服务器(server.com)
根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中 。这样一来,任何 DNS 服务器就都可以找到并访问根域 DNS 服务器了 。
因此,客户端只要能够找到任意一台 DNS 服务器 ,就可以通过它找到根域 DNS 服务器 ,服务器租用然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器 。
3.2 域名解析的工作流程浏览器首先看一下自己的缓存里有没有 ,如果没有就向操作系统的缓存要,还没有就检查本机域名解析文件 hosts ,如果还是没有 ,就会 DNS 服务器进行查询,查询的过程如下:
客户端首先会发出一个 DNS 请求 ,问 www.server.com 的 IP 是啥,亿华云并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址) 。本地域名服务器收到客户端的请求后 ,如果缓存里的表格能找到 www.server.com ,则它直接返回 IP 地址 。如果没有 ,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的 ,它不直接用于域名解析 ,但能指明一条道路。根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理” ,我给你 .com 顶级域名服务器地址给你 ,你去问问它吧。”本地 DNS 收到顶级域名服务器的地址后 ,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址 ,你去问它应该能问到” 。本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀 ?” server.com 的权威 DNS 服务器 ,它是域名解析结果的原出处。为啥叫权威呢 ?就是我的域名我做主。权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS 。本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接,同时本地 DNS 缓存该 IP 地址,这样下一次的解析同一个域名就不需要做 DNS 的迭代查询了 。至此,我们完成了 DNS 的解析过程 。现在总结一下,整个过程画成了一个图 。

DNS 域名解析的过程蛮有意思的,整个过程就和我们日常生活中找人问路的过程类似 ,只指路不带路。
3.3 vivo短视频所做的优化弄清了域名解析的工作流程 ,将vivo域名和头部厂商域名进行对比分析 ,发现vivo短视频域名解析耗时不稳定 ,波动范围很大 ,怀疑是某些地区用户访问量少,本地DNS服务器缓存命中率低导致的 ,因此我们的优化思路就是 提高本地DNS缓存命中率。

如上图所示 ,提高DNS缓存命中率一个简单的办法就是添加全国范围内的拨测任务,来进行DNS加热 。
通过对调整前后的DNS解析时间进行比较,可以看到耗时降低了30ms左右。

四 、HTTP性能
这里简单对比下 HTTP/1 、HTTP/2、HTTP/3 的性能 。
HTTP 协议是基于 TCP/IP ,并且使用了「请求 - 应答」的通信模式 ,所以性能的关键就在这两点里 。
1. 长连接
早期 HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求 ,都要新建一次 TCP 连接(三次握手),而且是串行请求 ,做了无谓的 TCP 连接建立和断开 ,增加了通信开销 。
为了解决上述 TCP 连接问题 ,HTTP/1.1 提出了长连接的通信方式 ,也叫持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销 ,减轻了服务器端的负载 。
持久连接的特点是 ,只要任意一端没有明确提出断开连接 ,则保持 TCP 连接状态 。

2. 管道网络传输
HTTP/1.1 采用了长连接的方式 ,这使得管道(pipeline)网络传输成为了可能。
即可在同一个 TCP 连接里面 ,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面 ,先发送 A 请求,然后等待服务器做出回应 ,收到后再发出 B 请求 。管道机制则是允许浏览器同时发出 A 请求和 B 请求 。

但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求。要是 前面的回应特别慢,后面就会有许多请求排队等着。这称为「队头堵塞」。
3. 队头阻塞
「请求 - 应答」的模式加剧了 HTTP 的性能问题。
因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时 ,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是「队头阻塞」。好比上班的路上塞车。

针对上面的 HTTP/1.1 的性能瓶颈 ,HTTP/2 做了一些优化 。而且因为 HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的 。
4.2 HTTP/2 相比 HTTP/1.1 性能上的改进:1. 头部压缩
HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么 ,协议会帮你消除重复的部分。
这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表 ,生成一个索引号 ,以后就不发送同样字段了,只发送索引号 ,这样就提高速度了 。
2. 二进制格式
HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文 ,而是全面采用了二进制格式。
头信息和数据体都是二进制 ,并且统称为帧(frame):头信息帧和数据帧 。

这样虽然对人不友好 ,但是对计算机非常友好,因为计算机只懂二进制,那么收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率 。
3. 数据流
HTTP/2 的数据包不是按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应 。因此,必须要对数据包做标记 ,指出它属于哪个回应。
每个请求或回应的所有数据包,称为一个数据流(Stream)。
每个数据流都标记着一个独一无二的编号 ,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数 。
客户端还可以指定数据流的优先级 。优先级高的请求,服务器就先响应该请求 。
4. 多路复用
HTTP/2 是可以在一个连接中并发多个请求或回应 ,而不用按照顺序一一对应。
移除了 HTTP/1.1 中的串行请求,不需要排队等待,也就不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接的利用率 。
举例来说,在一个 TCP 连接里,服务器收到了客户端 A 和 B 的两个请求 ,如果发现 A 处理过程非常耗时,于是就回应 A 请求已经处理好的部分 ,接着回应 B 请求,完成后,再回应 A 请求剩下的部分。

5. 服务器推送
HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式 ,服务不再是被动地响应,也可以主动向客户端发送消息。
举例来说 ,在浏览器刚请求 HTML 的时候 ,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端 ,减少延时的等待,也就是服务器推送(Server Push ,也叫 Cache Push) 。
4.3 那么HTTP/2 有哪些缺陷?HTTP/3 做了哪些优化?HTTP/2 通过头部压缩 、二进制编码、多路复用 、服务器推送等新特性大幅度提升了 HTTP/1.1 的性能,而美中不足的是 HTTP/2 协议是基于 TCP 实现的,于是存在的缺陷有三个 。
TCP 与 TLS 的握手时延迟;队头阻塞;网络迁移需要重新连接;1. TCP 与 TLS 的握手时延迟
对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的 ,分别属于内核实现的传输层、openssl 库实现的表示层 ,因此它们难以合并在一起 ,需要分批次来握手,先 TCP 握手,再 TLS 握手。
发起 HTTP 请求时,需要经过 TCP 三次握手和 TLS 四次握手(TLS 1.2)的过程,因此共需要 3 个 RTT 的时延才能发出请求数据。

另外 , TCP 由于具有「拥塞控制」的特性,所以刚建立连接的 TCP 会有个「慢启动」的过程 ,它会对 TCP 连接产生"减速"效果。
2. 队头阻塞
HTTP/2 实现了 Stream 并发,多个 Stream 只需复用 1 个 TCP 连接,节约了 TCP 和 TLS 握手时间,以及减少了 TCP 慢启动阶段对流量的影响 。不同的 Stream ID 才可以并发,即使乱序发送帧也没问题 ,但是同一个 Stream 里的帧必须严格有序。另外,可以根据资源的渲染顺序来设置 Stream 的优先级 ,从而提高用户体验 。
HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,看似很完美了,但是 HTTP/2 还是存在“队头阻塞”的问题 ,只不过问题不是在 HTTP 这一层面 ,而是在 TCP 这一层。
HTTP/2 多个请求是跑在一个 TCP 连接中的 ,那么当 TCP 丢包时,整个 TCP 都要等待重传,那么就会阻塞该 TCP 连接中的所有请求 。
因为 TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且有序的,如果序列号较低的 TCP 段在网络传输中丢失了 ,即使序列号较高的 TCP 段已经被接收了,应用层也无法从内核中读取到这部分数据 ,从 HTTP 视角看,就是请求被阻塞了。
举个例子,如下图:

图中发送方发送了很多个 packet ,每个 packet 都有自己的序号,可以认为是 TCP 的序列号,其中 packet 3 在网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是接收方的应用层就无法从内核中读取到,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取到数据,这就是 HTTP/2 的队头阻塞问题 ,是在 TCP 层面发生的 。
3. 网络迁移需要重新连接
一个 TCP 连接是由四元组(源 IP 地址,源端口 ,目标 IP 地址,目标端口)确定的,这意味着如果 IP 地址或者端口变动了 ,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WIFI 。
这些问题都是 TCP 协议固有的问题 ,无论应用层的 HTTP/2 在怎么设计都无法逃脱。
要解决这个问题 ,HTTP/3 就将传输层协议从 TCP 替换成了 UDP,并在 UDP 协议上开发了 QUIC 协议,来保证数据的可靠传输。

另外 HTTP/3 的 QPACK 通过两个特殊的单向流来同步双方的动态表,解决了 HTTP/2 的 HPACK 队头阻塞问题 。
不过 ,由于 QUIC 使用的是 UDP 传输协议 ,UDP 属于“二等公民”,大部分路由器在网络繁忙的时候 ,会丢掉 UDP包,把“空间”让给 TCP 包 ,所以 QUIC 的推广之路应该没那么简单。期待,HTTP/3 正式推出的那一天