Superlin的读书笔记

第10章:web性能要点

  • 12bet,延时和带宽对web性能的影响
  • TCP对HTTP的限制
  • HTTP自身的功能和缺陷
  • Web应用的发展趋势及性能要求

10.1 超文本,网页和web应用

  • 12bet,超文本文档
  • 富媒体网页:支持多媒体,如图片和音频
  • web应用:ajax,交互式web应用

10.2 12bet,剖析web应用

现代的we应用的平均请求数为90

时间与用户感觉:

  • 0~100ms:很快
  • 100~300ms:有一点点慢
  • 300~1000ms:机器在工作呢
  • > 1000ms:先干点别的
  • > 10000ms:不能用了

12博体育,超过1s,12bet,用户心思就会转移到其他任务,超过10s,除非有反馈,否则用户基本上会终止任务

http请求由很多独立的阶段组成:DNS解析,TCP握手,TLS协商(必要时),12博体育,发送HTTP请求

10.3 带宽和延迟

web应用主要有三个任务:取得资源,页面布局和渲染,Javascript执行

更多的带宽不大重要,延迟才是性能瓶颈,如下图所示

带宽和延时的关系

10.4 真实的用户性能度量

影响用户体验的一些方面:

  • 场景和页面选择:很难重复真实用户的导航模式
  • 浏览器缓存:用户缓存不同,性能差别很大
  • 中介设施:中间代理很缓存对性能影响很大
  • 硬件多样化:不同的CPU,GPU和内存比比皆是
  • 浏览器多样化:各种浏览器版本,有新有旧
  • 上网方式:真实连接的带宽和延迟可能不断变化

Navigation Timing API:可以查询到DNS和TCP连接时间 navigation timing

window.performance对象

function init() {
  // 1.存储时间戳
  performance.mark("startTask1");
  // 2.执行应用代码
  applicationCode1();
  performance.mark("endTask1");
  logPerformance();
}
function logPerformance() {
  var perfEntries = performance.getEntriesByType("mark");
  // 3. 迭代和记录用户计数数据
  for (var i = 0; i < perfEntries.length; i++) {
    console.log("Name: " + perfEntries[i].name +
                " Entry Type: " + perfEntries[i].entryType +
                " Start Time: " + perfEntries[i].startTime +
                " Duration: "   + perfEntries[i].duration  + "n");
  }
  // 4.记录当前页面的Navigation Timing对象
  console.log(performance.timing);
}

10.5 优化建议

核心优化策略:

  • 基于文档的优化:优先获取资源,提前解析
  • 推测性优化:预先解析DNS,预先连接可能的目标

优化技术:

  • 资源预取和排定优先次序:声明各个资源的优先级
  • DNS预解析:通过学习导航历史,用户鼠标悬停,或其他页面信号来触发
  • TCP预连接:DNS解析后用户可以预测的HTTP请求,推测性的打开TCP连接
  • 页面预渲染:在隐藏的标签页预先渲染整个页面

除了页面结构的优化,还可以在文档中嵌入提示,以触发浏览器的优化机制:

<!-- 预解析特定域名 -->
<link rel="dns-prefetch" href="//hostname_to_resolve.com">
<!-- 预取得页面后面要用到的关键性资源 -->
<link rel="subresource"  href="/javascript/myapp.js">
<!-- 预取得将来导航要用到的资源 -->
<link rel="prefetch"     href="/images/big.jpeg">
<!-- 根据用户下一个目标的预测,预渲染特定页面 -->
<link rel="prerender"    href="//example.org/next_page.html">

第11章:HTTP 1.x

增加的特性:

  • 持久化连接以支持连接重用
  • 分块传输编码以支持流式响应
  • 请求管道以支持并行请求处理
  • 字节服务以支持基于范围的资源请求
  • 改进的更好的缓存机制

针对网络的优化:

  • 减少DNS查询
  • 减少HTTP请求
  • 使用CDN
  • 添加Expires首部并配置ETag标签
  • Gzip资源
  • 避免HTTP重定向

11.1 持久连接的特点

每个TCP连接都要有三次握手,要经历一次客户端与服务器间完整的往返,持久连接就是HTTP请求结束后并不会立刻关闭HTTP连接,这样下一次的请求就不需要再经历三次握手。

通过首部 Connection: Keep-Alive

单独通过tcp连接获取html和css文件的情况如下图

单独通过tcp连接获取html和css文件

通过持久连接获取html和css文件的情况如下图

通过持久连接下载文件

N次请求节约N-1次RTT

11.2 HTTP管道

持久连接可以重用已有的连接,但是必须严格满足先进先出(FIFO)的队列顺序:发送请求,等待响应完成,再次发送客户端队列中的下一个请求。

HTTP管道将FIFO队列从客户端(请求队列)迁移到服务器(响应队列),串行 HTTP管道发送请求,服务端按FIFO处理

如果服务器并行处理下载文件请求,并行 通过管道发送请求,服务器并行处理

即使客户端同时发送两个请求,而且css资源先准备完毕,服务器也会先发送html响应,再交付css,这种情况叫队首阻塞

问题:

  • 一个慢响应会阻塞后续所有请求
  • 并行处理请求时,服务器必须缓存管道中所有的请求,从而占用服务器资源,如果有的请求非常大,则很容易形成服务器的受攻击面
  • 响应失败可能终止tcp连接,从而强迫客户端重新发送所有的后续资源请求,导致重复处理
  • 可能存在中间代理,因此要检测管道的兼容性,确保可靠性很重要
  • 如果中间代理不支持管道,那么可能会中断连接,也可能会把所有请求串联起来

11.3 使用多个TCP连接

大多数现代浏览器,都支持每个主机打开6个连接(对于同一个域名),这一限制主要是防止客户端消耗掉服务器的所有资源

6个连接的限制,也是符合公平原则的,保证每个客户端都有机会与服务器建立连接,不会因为某些客户端占用过多的连接,从而使得有些客户端得不到连接

11.4 域名分区

目前平局每个页面都包含90多个独立的资源,如果都来自同一个主机,就会导致排队,可以将资源分散到多个子域名:{share1,share2}.example.com,由于主机名不一样了,就可以突破浏览器连接的限制,实现更高的并行能力。

缺点:每个新主机名都要求有一次额外的dns查询(对移动客户端影响更大),每多一个套接字都会多消耗两端的资源,而且必须手工分散这些资源托管于多个主机上

11.5 度量和控制协议开销

http请求都会携带额外的500~800字节的http元数据:用户代理字符串,很少改变的首部,缓存指令等。此外还有一大块的Cookie

11.6 连接与拼合

拼接:将多个javascript或css文件合并为一个文件 拼合:把多张图片组合成一个更大的复合的图片

浏览器是以递增的方式处理html的,但是对于javascript和css的解析和执行,则要等到整个文件下载完成,javascript和css处理器都不允许递增式执行

前面这段话理解并不难,html只是标记,各个tag比较独立,前面的tag和后面的tag不会互相影响;

但是javascript有声明提升机制,定义在文件后面的方法,可以在文件的前面就调用;

而css有选择器优先级的限制,只有编译整个css文件才能综合的确定某个元素的样式

11.7 嵌入资源

嵌入资源是一种十分流行的优化方法,把资源嵌入文档可以减少请求的次数,比如javascript和css代码可以通过script和style标签直接嵌入页面中,图片甚至是音频或pdf文件,可以通过数据URI(data:[mediatupe][;base64],data)的方式嵌入页面中

缺点

  • 无法被浏览器,cdn或其他缓存代理作为单独的资源缓存,也就是多个页面都嵌入同样的资源,这个资源将会随着每个页面的加载而被加载,从而增加了每个页面的总体大小
  • 如果缓存资源被更新,之前所有出现过它的页面都会被宣告无效,而由客户端重新从服务器获取
  • 编码后的资源比原来大33%

一般只考虑嵌入1~2kb以下的,最好是只在个别页面中使用,并且不是经常更新

第12章:HTTP 2.0

  • 更快,更简单,更健壮
  • 通过支持请求和响应的多路复用来减少延迟,通过压缩http将协议开销降到最低,增加对请求优先级喝服务器推送的支持
  • 新的流量控制,错误处理和更新机制
  • 改变了格式化数据(分帧)的方式,以及客户端与服务器间传输这些数据的方式

12.1-12.2

spdy是http 2.0的催化剂,使得页面加载时间提高了50%以上

http 2.0是http 1.1的拓展而不是代替,http 2.0增加了新的二进制分帧数据层,兼容1.1

12.3 设计与设计目标

12.3.1 二进制分帧层

http 2.0分帧结构

通过增加二进制分帧层来提高性能,将传输的消息分割为更小的消息和帧,并采用二进制编码

12.3.2 流,消息和帧

  • 流:已建立连接上的双向子节流
  • 消息:与逻辑消息对应的完整的一系列的数据帧
  • 帧:通信的最小单位,每个帧包含首部,至少会标识当前帧所属的流

流,消息和帧

所有的http 2.0通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后根据每个帧首部的标识符重新组装

对这三个概念的理解

  • 所有通信都在一个tcp连接上完成
  • 流是连接中的一个虚拟信道,可以承载双向信息,每个流都有一个唯一的整数标识符
  • 消息是指逻辑上的http消息,比如请求响应等,由一个或多个帧组成
  • 帧是最小的通信单位,承载着特定类型的数据,如首部,负荷等

12.3.3 多请求与响应

http 1.x 会导致队首阻塞,http 2.0 突破了这个限制,客户端和服务器可以将 http 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端将他们重新组合起来,提高了 tcp 连接的效率

http 2.0连接

12.3.4 请求优先级

每个流都带有一个31比特的优先级:

  • 0表示最高的优先级
  • 2^31-1表示最低的优先级

服务器可以根据优先级,对于不同的流采用不同的处理策略,优先级高的优先分配资源

12.3.5 每个来源一个连接

所有http 2.0连接都是持久化的,服务器与客户端只需要一个连接即可

每个来源一个连接显著减少了资源占用:套接字管理工作量少了,内存占用减少了,连接吞吐量减少了,好处:

  • 所有流的优先次序始终如一
  • 压缩上下文单一使得压缩效果好
  • tcp连接少使得网络拥塞状况得以改观
  • 慢启动时间减少,拥塞和丢包恢复速度更快

12.3.6 流量控制

http 2.0流量控制机制:

  • 基于每一条进行,而不是端到端控制
  • 基于窗口更新帧进行,即接收方广播自己准备接收某个数据流的多少字节,以及整个连接要接收多少字节
  • 流量控制窗口大小通过WINDOW_UPFATE帧更新,这个字段指定了流ID和窗口大小递增值
  • 流量控制有方向性,即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小
  • 流量控制可以由接收方禁用,包括整对整个连接

12.3.7 服务器推送

服务器推送就是服务器可以对一个客户端的请求发送多个响应,就是除了对最初的请求响应外,服务器还可以额外向客户端推送资源,而不需要客户端明确请求

服务器推送

  • 客户端可以缓存推送过来的资源
  • 客户端可以拒绝推送过来的资源
  • 推送资源可以由不同的页面共享
  • 服务器可以按照优先级推送资源

12.3.8 首部推送

http 2.0会压缩首部元数据:

  • http 2.0在客户端和服务器使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送
  • 首部表在http 2.0的连接存续期内始终存在,由客户端和服务器共同渐进地更新
  • 每个新的首部键值对要么被追加到当前表的末尾,要么替换表中之前的值

首部压缩

12.3.9 有效的http升级与发现

通过Upgrade机制来协调适当的协议:

发送升级到http 2.0的请求

GET /page HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: HTTP/2.0                    // 升级到http 2.0
HTTP2-Settings: (SETTINGS payload)   // http 2.0 settings净荷的base64 url编码

服务器不支持http 2.0,返回http 1.1响应

HTTP/1.1 200 OK           // 不支持http 2.0
Content-length: 243
Content-type: text/html
(... HTTP 1.1 response ...)

支持http 2.0告诉客户端可以用http 2.0

HTTP/1.1 101 Switching Protocols // 接收http 2.0升级,切换到新的分帧
Connection: Upgrade
Upgrade: HTTP/2.0
(... HTTP 2.0 response ...)

如果客户端保存了关于 http 2.0 的支持信息,可以直接发送 http 2.0 分帧,而不必使用 Upgrade 机制

12.4 二进制分帧介绍

分帧首部

  • 16位的长度意味着一帧大约可以携带64kb数据,部包括8字节的首部
  • 8位类型决定如何解释帧其余部分的内容
  • 8位标识允许不同的帧类型定义特定于帧的消息标志
  • 1位保留字段始终为0
  • 31位的流标识符唯一标识http 2.0的流

http 2.0规定了如下帧类型

  • DATA:用于传输http消息
  • HEADERS:用于传输关于流的额外的首部字段
  • PRIOITY:用于指定或重新指定引用资源的优先级
  • RST_STREAM:用于通知流的非正常终止
  • SETTINGS:用于通知两端通信方式的配置数据
  • PUSH_PROMISE:用于发出创建流和服务器引用资源的要约
  • PING:用于计算往返时间,执行“活性”检查
  • GOAWAY:用于通知对端停止在当前连接中创建流
  • WINDOW_UPDATE:用于针对个别流或个别连接实现流量控制
  • CONTINUTION:用于继续一系列的首部片段

12.4.1 发起新流

由两种情况会发起新流:

  • 客户端发送HEADERS帧来发起新流,这个帧包含带有新流ID的公用首部,可选的31位优先值,以及一组http键值对首部
  • 服务器通过发送PUSH_PROMISE帧来发起推送流,这个帧与HEADERS帧等效,但它要包含“要约流ID”,没有优先值

带有优先级的headers帧

12.4.2 发送应用数据

数据格式基本的二进制分帧结构一样,没有优先级标识

DATA帧的长度字段决定每帧净荷最多可达2^16-1(65535)字节,但是为了减少队首阻塞,http 2.0标准要求DATA帧不要超过2^14-1(16383)字节,长度超过阀值就会分帧发送

12.4.3 http 2.0帧数据流分析

同时发送请求和响应

  • 有3个活动的流:stream1,stream3和stream5
  • id都是奇数,也就是都是由客户端发起,这里没有服务器发起的流
  • 服务器发送的stream1包含多个DATA帧,而且之前已经发送过HEADERS帧
  • 服务器交错发送stream1的DATA帧和stream3的HEADERS帧,这就是响应的多路复用
  • 客户端在发送stream5的DATA帧,表明HEADERS帧之前已经发送过