HTTP深入学习总结(3)——连接管理(上)

分类: 开发技术 | 作者: 尼莫船长 | 发表于 2013/10/12 2条评论


由于HTTP连接管理涉及到很多网络通讯的知识,且很多时候都会被java程序员忽略掉,所以会分成几章来更新这部分的知识。
连接管理大体上分四大部分:
1,HTTP是如何使用TCP链接的
2,TCP链接的时延、瓶颈以及存在的障碍
3,HTTP的优化,包括并行、Kepp-alive和管道化管理
4,管理链接应该做和不应该做的事

1.1 TCP是可靠的数据管道

首先,世界上基本上所有的HTTP协议都是基于TCP/IP协议栈的,即 HTTP over TCP over IP 协议栈模式。
一旦客户端生成一个Http报文,那么可能客户端就会打开一条TCP/IP链接,链接某一个服务器,且一旦建立链接,报文在c/s之间传输就永远不会消失。

假如,我们有如下的一个Request:

http://www.abcshop.com:80/get-list.html

当浏览器收到这个请求的时候,会进行如下7个步骤来完成:
1> 浏览器解析出主机名: www.abcshop.com
2> 浏览器查询这个主机的IP地址: 110.120.130.1
3> 浏览器获得端口号: 80
4> 浏览器发起和 110.120.130.1的 80端口的链接: Client —(internet)—> Server
5> 浏览器向服务器发送一条HTTP GET报文: Client —(internet)—> Server
6> 浏览器从服务器读取HTTP Response: Client <—(internet)— Server 7> 浏览器关闭链接

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

前文我们说过 HTTP over TCP over IP模式, 而安全版本的HTTPS协议,就是在HTTP和 TCP层之间插入了一个密码加密层(TLS or SSL) 即变成 HTTP over (TLS or SSL) over TCP over IP模式

当HTTP要传输一个报文的时候,就有以流的形式来承载要传输的内容,流通过打开的TCP链接按顺序传输。当TCP收到收到数据之后,会把数据流分成段(segment)的小数据库,然后封装在IP分组中,通过因特网传输。

由于每个TCP段都是由IP承载,所以,每个IP分组中都包括以下3部分:
1> 一个IP分组首部(通常20字节)
2> 一个TCP段首部(通常20字节)
3> 一个TCP数据块(0或多个字节)

下面通过一个完整的HTTP数据协议包来说明:(抓包软件为开源的强悍的数据包分析软件Wireshark,推荐安装)

0>找到一个HTTP包
HTTP1

1>这是一个物理层的ARP首部,要低于IP层,14字节

HTTP2
2>上文提到的一个IP分组首部,20字节
HTTP3

3>一个TCP段首部,20字节
HTTP4

4>TCP数据块,可以看到这个HTTP协议 被分割为2个segment进行传输
HTTP5

分析完这个HTTP数据包以后,我们会得出一个结论,在因特网上传输的TCP数据包,只要是应用层协议(和HTTP是同层),我们都可以用这样的方法去分析和抓包,所以,在Unix/Linux上使用snoop工具抓包的时候,经常会加上一个参数 -x54
为什么呢? 就是要掠过一个数据包的ARP首部、IP首部、TCP首部这些对我们来说基本上没有用的信息,直接获取TCP数据块,即应用层的数据包进行分析。
那么关于TCP运行的原理和基于TCP/IP的socket编程内容就略去不讲,可以参考《TCP/IP详解》这个经典大部头……

2.1 HTTP性能问题
关于HTTP的时延,下图是一个串行的HTTP事物时间线,
HTTPdelay
HTTP比较耗时的:
1> DNS解析,如果你的DNS server不给力,那么这个请求过程会相当漫长,几十秒都有可能。所以国内目前最火的互联网服务商之一DNSpod就是提升对国外主机/空间进行解析速度的,本空间就是利用了DNSpod的免费服务,服务器在香港,而国内访问速度几乎体会不到差异,给一个赞!
2> 然后clinet会向Server发送一个TCP连接请求,并且等待server的应答,一般来说1,2秒足够,但是如果多个client并发时,server的压力增大,这个等待时间值会飞快的叠加上去……
3> 建立TCP连接,就要开始HTTP的请求-应答阶段了,server处理请求,网络传输报文,这毫无疑问会耗费时间。
4> 最后,server会回送HTTP应答,这也需要时间。

2.2 性能关注点
以下几点是programmer需要注意的HTTP性能控制点,我们会分别讨论和分析
1> TCP建立握手
2> TCP慢启动阻塞控制
3> 数据聚集的Nagle算法
4> 用于捎带确认的TCP延迟确认算法
5> TIME_WAIT时延和端口耗尽

2.2.1 TCP握手时延
在Client和Server建立TCP握手过程中,一般包含3~4个步骤,下图就是整个过程(由于这个HTTP应用没有使用cache,所以其实缺少了第四个步骤,server没有返回类似 304 not modified这样的请求)
TCP握手1

1> clinet发送一个TCP分组包,其中包含SYN标记
2> Server接收了链接请求之后,会计算连接参数,然后会送一个TCP分组,包含SYN和ACK标记位
3> Client向Server发送一条确认信息,通知Server链接建立,包含ACK标记
4> 由于第三步中ACK分组可以放入一个HTTP请求报文,所以其实Server可以根据请求发送一个Response

以上就是TCP握手时延,而整个握手过程可能会浪费一个HTTP事务大约50%的时间,所以这是一个可以优化的关键点,后续文章会讨论如何利用已有链接进行HTTP Request-Response 传输,减少TCP握手带来的性能损耗。

2.2.2 延迟确认

由于TCP允许回传的数据包对发往同方向的数据进行“捎带”,类似于“异步窗口”的设计理念,在TCP在一定时延内(如100~200毫秒),之前存放在Socket的buffer中的相应信息可以借由别的发往客户端的数据包“捎带”,这样能够最大化的运用网络资源。
但是! 由于HTTP是双峰的传输,有req必有resp,所以,这种TCP的原有设计模式对HTTP是不能用的,放到buffer里面的等待被捎带给Client的Response几乎是一定会过期的,根据OS的实际情况,我们需要关闭或者调整TCP的延迟算法!

2.2.3 TCP慢启动

在TCP设计的过程中,有age这个概念,TCP会随着时间进行自我调节,建立链接初期会限制连接的最大速度,如果数据传输成功,会随着时间推移,不断增加传输速度,这个特性被称之为“TCP慢启动(Slow Start)”,用于防止internet的阻塞和过载。
TCP的慢启动限制了一个TCP节点在任意时刻的传输数据数量,如果成功传输一个分组,发送端就会获取发送另外两个分组的权限,两个成功,获取4个发送权限,依此例推,这种方式被称为“打开阻塞窗口”(opening the congestion window)

由于这种TCP的限制存在,所以,新建立的TCP链接的传输速度会比已经传输过数据的TCP链接要慢一些,但是HTTP有利用这些已经存在的链接的方式,这部分内容放到后面来讲。

2.2.4 Nagel算法与TCP_NODELAY

TCP数据流接口允许发送任意字节的数据,但是每个TCP首部就至少包含了40Byte的头信息,如果网络之间大量的发送分组信息,会给网络带来极大的性能损耗,一般LAN中允许的最大的数据包是 1500Byte, 所以Nagel算法就会堆积一些小的数据包,然后一次性的发送出去,但是HTTP如果是很小的报文,就可能在相当长时间内不能填满这个buffer,从而导致HTTP的报文过期(比如超过200ms以后),为了解决这个问题,HTTP应用中可以设置一个参数:
TCP_NODELAY , 这个参数可以使Nagel算法失效,即便是几Byte的HTTP报文也可以直接发送出去,而不用等待。

2.2.5 TIME_WAIT累积和端口耗尽

这个问题曾经在自己的实际工作中遇到过,我们的WebService的处理能力非常强大的情况下,我们采用了大并发Client访问的情况,目的是测试Server端的最高性能,但是程序跑一会以后,发现response的失败情况不停的增加,而且都会返回失败的状态码。通过命令行查看发现网络正常,但是几乎所有的端口都会处于 TIME_WAIT状态,这是怎么回事呢?

TCP在设计的时候,会有这样的一个机制,当TCP关闭的时候,会在内存中保留一个记录,记录最近关闭的IP和port,但是这个时间只会保留一小段时间,就会被自动清除,通常是预估的sagment的最大使用周期的2倍,又被称为2MSL,通常是2分钟左右,以保证在这段时间内没有新IP连接到这个端口中。因为早期的因特网路由器性能比较差,设计者估计每个Segment在因特网中存留时间不会超过1分钟,所以,设定了这个值,但是现在路由器和网络环境要强悍的多,这个生存周期就大大缩短了 。
于是,问题就产生了,我们知道计算机的端口一共有65535个,假如是一个clinet 连 一个server,IP固定,那么只有Server的端口号可以变化,假如我们可以利用的Server的端口号有60000个,那么在2MSL内,我们只能处理的Clinet的请求大约为 60000端口 / 120秒 = 500 次请求/秒 通过计算,我们发现由于这个2MSL的存在,严重限制了我们的HTTP应用性能,可以做的优化:
1> 如我们可以非常小心的调整2MSL的时间间隔,LINUX/Unix的内核参数之一,如果调小,可能带来的弊端就是,一个TCP链接可能会被另一个同IP/port的TCP链接干扰,插入“脏数据”,甚至拖慢整个OS的性能。
2> 我们可以采用在clinet/server 之间设置多个虚IP来增加IP/port链接组合,或者直接增加Clinet机器的数量。

最后一个图,为整个HTTP链接建立并且进行请求-应答的全过程抓包。
HTTP全过程

移动设备快速阅读本文:
  请扫描二维码  -->

假如青春是一种缺陷的话,那也是我们太快就会失去的缺陷。 ——洛威尔

» 本文链接地址:http://www.wanghaoyan.com/?p=171 » 英雄不问来路,转载请注明出处,谢谢。
» 您也可以订阅本站:RSS 2.0

Tag:
  1. “IP固定,那么只有Server的端口号可以变化 ” 这边难道不是应该 只有Client的端口号可以变化 么。。

  2. 还有想请教下 由于HTTP是双峰的请求-应答行为降低了捎带信息的可能 这边不太理解。。

« »