关于首屏html应限制在14kb内的探究

2,250 阅读6分钟

我们在调研优化网页加载性能时,通常能看到这样一条:html 最好限制在 14kb 以内。那么问题来了,为什么是 14kb,超过 14kb 对性能的影响有多大,为了回答这两个问题,进行了一些调研与测试。从下面的概念开始。

相关概念

  • cwnd(Congestion Window)

    即最拥塞窗口,慢启动中引入的概念,表示发送方在得到接收方确认前,最大允许传输的数据大小。

  • RTT(Round-Trip Time)

    即往返时延,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

  • MTU(Maximum Transmission Unit)

    即最大传输单元,是指一种通信协议的某一层上所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口有关(网络接口卡、串口等)。对于时下大多数以太网的局域网来说,最大 MTU 为 1500 字节。但是像 PPPoE 这样的系统会减小这个数值,通常是 1492 = 1500 - 2(PPP) - 6(PPPoE)。

  • MSS(Maximum Segment Size)

    即最大分段大小,是传输控制协议(TCP)的一个参数,以字节数定义一个计算机或通信设备所能接受的分段的最大数据量。 它并不会计算 TCP 或 IP 协议头的大小。 一个 TCP 包(数据段)的荷载 <= MSS < MTU。

    PPPoE 首部 6,PPP 协议 2 数据链路层最大 data 为 1500-6-2=1492 IPv4 首部最少 20,IPv6 首部 40,TCP 首部最少 20 MSS 最大为 1492-20-20=1452 字节

慢启动

在网络的实际传输过程中如果不加以控制,就很容易出现堵塞的现象,就像热门景区,如果不对车流进行控制,很快交通就会堵塞,最后瘫痪。因此 TCP 在设计时考虑到了这一点,会使用一些算法来避免网络拥塞、丢包等,主要包括:1)慢启动,2)拥塞避免,3)快速重传,4)快速恢复。

慢启动是 Van Jacobson 在 1988 年提出的,其主要目的是用来防止宽带被迅速打满。其原理如下:

  • 连接建好的开始先初始化 cwnd = 1,表明可以传一个 MSS 大小的数据。

    最初,cwnd 的值只有一个 TCP 段,1999 年 RFC2581 增加到 4 个 TCP 段,2013 年 RFC6928 将其提高到了 10 个 TCP 段,也就说现在可以初始化 10 * MSS 大小的数据,约为 14kb。

  • 每当收到一个 ACK,cwnd++; 呈线性上升

    服务器向客户端发送完 10 个 TCP 段后,必须停下来等待确认,此后,每当收到一个 ACK,慢启动算法就会告诉服务器可以将它的 cwnd 增加一个 TCP 段(一次发送 10 个 TCP 段,相当于增加 10 个 TCP 段)。

  • 每当过了一个 RTT,cwnd = cwnd*2; 呈指数让升

    每次收到 ACK,可以发送的数据量就会翻倍,呈指数让升。

  • 还有一个 ssthresh(slow start threshold)上限,当 cwnd >= ssthresh 时,就会进入“拥塞避免算法”

拥塞窗口大小增长示意图

由此,可以知道,由于慢启动的存在,网络传输的开始阶段并不能最大限度的利用宽带,而是一个动态调整的过程,在连接刚建好的第一个往返,最多只能传输 10 * MSS 大小的数据,如果超过这个大小(14kb),数据包就会被拆分,必须等到第一个往返结束后再进行传送,增大了传输时间,因此首屏 html 应限制在 14kb 内。

14kb 限制的测试

前面提到资源超过 14kb 会多次往返,延长了传输时间,为了探究 html 刚好超过 14kb 时(多一次往返)对网页性能的影响,进行了如下测试:

1)测试环境

fast 3g条件下进行测试,RTT为150ms。

[3GFast]
 label="3G Fast (1.6 Mbps/768 Kbps 150ms RTT)"
 bwIn=1600000(下行bps)
 bwOut=768000(上行bps)
 latency=150(延迟)
 plr=0(丢包率)
 timeout=120

2)测试的方法

通过内联 css 对 html 大小进行动态调整,对比不同资源大小下的加载时间(Load 时间)和首次内容绘制时间(FCP),着重观察跨越 14kb 前后的时间差。

基础html

3)测试结果

FCP和Load时间随html体积变化测试结果

可以看到 14kb 前后,FCP 和 Load 时间都没有太大变化,而 3g fast 下往返延时是 150ms,如果 html 超过 14kb 被分成两次传输,多一次往返,延时应该超过 150ms,Load 时间最少应该增加 150ms,而测试结果并没有体现出来,感觉很慌。于是用 wireshark 抓包看看,是不是有分片传输。

html大小为14574字节时的抓包示意图 可以看到,html并没有被拆分发送而只在27帧进行发送,再看MSS,为16344字节,并不是前述的14kb(小于1500字节)。我们知道1500字节这个MTU与网卡是有关系的,查看网卡信息,如下: 网卡信息

可以看到,mac 上我测试用的 lo0(回环网卡)的 mtu 为 16384,减去 ip 首部 20 和 tcp 首部 20,MSS 为 16344,也就是说 14574 字节的 html 并没有达到被拆包的大小阈值,没有对网页性能造成影响就说得过去,不慌了,不慌了。于是将 html 的大小增大至 16705(大于 16344),再进行测试,结果仍未有太大影响,加载时间仍在 650-660 之间徘徊,黑人问号脸,再抓包看看:

html大小为16705字节时的抓包结果

可以看到 html 被拆成了 19、20 两帧进行传输,确实是被拆分了,可结果仍不符合预期,用 chrome 的 performance、audit 多次进行测试,结果一样...

chrome 测试结果不准确?本地的 server 有问题?于是将测试 html 拷贝到远程服务器,用webpagetest在 3g fast 条件下测试。结果如下:

拆包前后测试对比图 从图中可以看到html从13kb增加14kb,拆分的TCP段多一个(当前网卡的MTU为1500)后,Load时间和FCP时间都增加超过了3g fast的150ms延时,符合预期。也就是说,在真实的场景,用户通过浏览器网址访问网页,慢启动所带来的影响还是较为明显的。对于chrome本地测试结果为什么不符预期,有时间再作研究。

结论

  • html 限制在 14kb 内是有必要的。
  • 当 MSS 的个数以及 MTU 增加后,14kb 的阈值也会相应提高。