HTTP连接管理(1)

连接管理

  从本节开始我们进入第三大块的学习:连接。虽然 HTTP 规范对 HTTP 报文有着详尽的解释,但对 HTTP 连接介绍的却不多,而作为 http 应用的开发人员需要对此有一定了解,现在让我们来开始吧。

TCP 连接

  世界上几乎所有的 HTTP 通信都是由 TCP/IP 承载的,TCP/IP 是全球计算机及网络设备都在使用的一种常用的 分组交换网络分层协议集 。客户端应用程序可以打开一条 TCP/IP 连接,连接到可能运行在世界任何地方的服务器应用程序,一旦连接建立起来, 在客户端和服务器的计算机之间交换的报文就永远不会丢失,受损或失序

TCP 的可靠数据通道

  HTTP 连接实际上就是 TCP 连接和一些使用连接的规则,TCP 连接是互联网的可靠连接。若想正确、快速地发送数据,就需要了解 TCP 的一些基本知识。

  TCP 为 HTTP 提供了一条可靠的比特传输管道,从 TCP 连接一端填入的字节会从另一端以原有的顺序正确地传送出来。

TCP 流是分段的,由 IP 分组传送

  TCP 的数据是通过名为 IP 分组(或 IP 数据报)的小数据块来发送的。这样,HTTP 就是“HTTP over TCP over IP”协议栈的最顶层了。它的安全版本 HTTPS 就是在 HTTP 和 TCP 之间插入了一个密码加密层(称为 TLS 或 SSL)

  HTTP 要传送一条报文时,会以流的形式将报文数据的内容通过一条打开的 TCP 连接按序传输。TCP 收到数据流之后,会将数据流砍成被称作的小数据快,并将段封装在 IP 分组中,通过互联网进行传输。所有的这些工作都是由 TCP/IP 软件来处理的,对 HTTP 开发人员来说,它什么都看不到。

每个 TCP 段是由 IP 分组承载,从一个 IP 地址发送到另一个 IP 地址的。每个 IP 分组中包括:

  • 一个 IP 分组首部(20 字节)
  • 一个 TCP 段首部(20 字节)
  • 一个个 TCP 数据块(0 个或多个字节)

IP 首部包含了源和目的 IP 地址、长度和其他一些标记。TCP 段的首部包含了 TCP 端口号,TCP 控制标记,以及用于数据排序和完整性检查的一些数字值。

保持 TCP 连接的正确运行

  在任意时刻计算机都可以有几条 TCP 链接处于打开状态。TCP 是通过端口号来保持所有这些连接的正确运行的。

  端口号类似于有些企业的电话分机号:公司的总部号码能将你接到前台,而分机号可以将你接到正确的员工位置。IP 地址可以将你连接到正确的计算机,而端口号则可以将你连接到正确的应用程序上去。TCP 连接是通过 4 个值来识别的:

  <源IP地址、源端口号、目的IP地址、目的端口号>

这 4 个值一起唯一地定义了一条连接,两条不同的 TCP 连接不能拥有 4 个 完全相同 的地址组件值。

用 TCP 套接字编程

  操作系统提供了一些操作其 TCP 连接的工具,这个套接字 API 向 HTTP 开发人员隐藏了 TCP/IP 的具体细节,它最初是为 Unix 操作系统开发的,但现在几乎所有的操作系统和语言中都有它的变体存在。套接字 API 允许用户创建 TCP 的端点数据结构,将这些端点与远端服务器的 TCP 端点进行连接,并对数据流进行读写。TCP API 隐藏了所有底层网络协议的握手细节,以及 TCP 数据流与 IP 分组之间的分段和重装细节。

对 TCP 性能的考虑

  HTTP 紧挨着 TCP,所以 HTTP 事物的性能很大程度上取决于底层 TCP 通道的性能。TCP 是个很复杂的话题,我们这一系列把重点放在 HTTP 上,以后有机会的话,会详细讨论 TCP 的细节。

HTTP 连接的处理

  暂时略过 TCP 的细节,我们把重点放在 HTTP 上来,现在将介绍 Connection 首部,这是 HTTP 连接管理中一个很容易被误解却又很重要的部分。

被误解的 Connection 首部?

  HTTP 允许客户端和最终的源端服务器之间存在一串 HTTP 中间实体(代理,高速缓存等)。可以从客户端开始,逐跳地将 HTTP 报文经过这些中间设备,转发到源端服务器上(或反向传输)。

  在某些情况,两个相邻的 HTTP 应用程序会为它们共享的连接应用一组选项。HTTP 的 Connection 首部字段中有一个由逗号分隔的连接符列表,这些标签为此连接指定了一些不会传播到其他连接中的选项。比较费解的是,Connection 可以承载 3 种不同类型的标签:

  • HTTP 首部字段名,列出了只与此连接有关的首部
  • 任意标签值,用于描述此连接的非标准选项
  • 值 close,用来说明操作完成之后需要关闭这条永久链接。

如果连接标签中包含了一条关于 HTTP 首部字段的名称,那么这个首部字段就包含了与一些连接有关的信息,不能将其转发出去 。在将报文转发出去之前,必须 删除 Connection 首部列出的所有首部字段 。由于 Connection 首部可以防止无意中对本地首部的转发,因此将逐跳首部名放入 Connection 首部被称为“对首部的保护”

串行事物处理时延

  如果只对连接进行简单的管理,TCP 的性能时延可能会叠加起来。比如假设有一个包含了三个嵌入图片的 web 页面。浏览器需要发起 4 个 HTTP 事物来显示此页面;1 个用于顶层的 HTML 页面,3 个用于嵌入的图片。如果每个事物都需要一条新的连接,那么连接延时就会叠加起来。

  除了串行加载引入的实际延迟外,加载一幅图片时,页面上其他地方都没有动静也会让人烦躁。另一个缺点是:有些浏览器在对象加载完毕之前无法获知对象的尺寸。

下面几种方案可以提高 HTTP 的连接性能:

  • 并行连接

通过多条 TCP 连接发起并发的 HTTP 请求

  • 持久连接

重用 TCP 连接,以消除连接及关闭时延

  • 管道化连接

通过共享的 TCP 连接发起并发的 HTTP 请求

  • 复用的连接

交替传送请求和响应报文(未实际应用)

并行连接

  HTTP 允许客户端打开多条连接,并行地执行多个 HTTP 事物。

并行连接可能会提高页面的加载速度

  包括嵌入对象的组合页面如果能克服单条链接的空载时间和带宽限制,加载速度也许会有提高。时延可以重叠起来,而且如果单条链接没有充分利用客户端的带宽,可以将未用带宽分配来装载其他对象。

并行连接不一定快

  客户端的网络带宽不足时,大部分的时间可能都是用来传送数据的。如果并行加载多个对象,每个对象都会去竞争这有限的带宽,每个对象都会以较慢的速度按比例加载,这样带来的提升就很小。

  而且打开大量连接会消耗很多内存资源,从而引发自身的性能问题。复杂的 web 页面可能会有数十上百个内嵌对象,客户端可能打开数百个连接,但 web 服务器通常需要同时处理很多其他用户的请求。这会导致服务器性能的严重下降,对高负荷的代理来说也同样如此。

  实际上,浏览器确实使用了并行连接,但它们会将并行连接的总数限制为一个较小的值(4 个)。服务器可以随意关闭来自特定客户端的超量连接。

持久连接

  web 客户端经常会打开到同一个站点的连接,而且相当一部分指向其他对象的超链接通常都指向同一个站点( 站点本地性

  因此,HTTP/1.1 允许 HTTP 设备在事物处理结束之后将 TCP 连接保持在打开状态,以便为未来的 HTTP 请求重用现存的连接。在事物处理结束之后仍然保持在打开状态的 TCP 连接被称为 永久连接

持久并行连接

  持久连接降低了时延和建立连接的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量。但是管理持久连接的时候要格外小心,不然会积累出大量的空闲连接,耗费本地以及服务器上的资源。

  持久连接与并行连接配合使用可能是 最高效的方式。现在很多 web 应用程序都会打开少量的并行连接,其中的每一个都是持久连接。持久连接有两种类型,比较老的 HTTP/1.0+ "keep-alive" 连接,以及先进的 HTTP/1.1 “persistent”连接。

  未完待续,下一小节会详细介绍这两个连接。