转载请注明出处 http://www.paraller.com
原文排版地址 点击获取更好阅读体验
核心知识点
- HTTP协议 实际上是
TCP连接
+ HTTP使用规则
, 所以HTTP只是一个应用层协议. - TCP 为HTTP提供一条可靠的比特传输管道,按序无差错的传输。
- HTTPS就是在 HTTP和TCP之间插入一个密码加密层
- TCP是通过名为 IP分组(或IP数据报) 的
小数据块
来发送的 - TCP是通过四个值来识别的
源IP地址、源端口号、目的IP地址、目的端口号
;两条不同的TCP连接不能拥有完全相同是四个值
HTTP传输流程
- 将报文数据通过流数据的形式,通过TCP传输
- TCP收到数据流之后,将数据流分成小数据块,简称
段
- 将段封装在IP分组中,通过因特网进行传输
IP分组的组成
- IP分组首部(通常20字节): 源和目的IP地址、长度、和其他标记
- TCP段首部(通常20字节): TCP端口号、TCP控制标记、用户数据排序和完整性检查的数字值
- TCP段数据(0或更多): 流数据内容
套接字编程
套接字API允许创建TCP的端点数据结构,将这些端点与远程服务器的TCP端点进行通信,进行数据的读写,隐藏了握手细节,以及TCP数据流与IP分组之间的细节
HTTP事务的性能很大程度取决于TCP的性能,
HTTP事务的时延
一个完成的HTTP事务过程 : DNS查询 – 建立TCP连接 – 发起请求 – 事务处理 – 接收响应 – 关闭连接
其中事务处理的耗时是很短的(除非应用服务器过载)
性能聚焦区域:
常见的一些TCP相关
时延
TCP连接建立握手
在建立新的TCP连接,甚至是在发送任意数据之前,TCP软件会交换一系列的IP分组, 对连接的有关参数进行沟通
, 如果连接之传输少量的数据,这个交换过程会严重降低HTTP的性能。
三次握手机制:
- 客户端会发送一个包含SYN标记的TCP分组给服务端,代表这个是连接请求
- 服务端收到这个分组之后,会对连接参数进行计算,并回送一个带有 SYN和ACK标记的分组。代表请求已经被接受
- 客户端回送服务器一个带有 ACK标记分组,通知服务器连接已经成功建立(现在的TCP栈可以在这个分组中
发送数据
)
通常HTTP事务的交换的数据不多,小的事务可能在TCP的建立上花费了50%的时间。
解决方案:
用于捎带确认的 TCP延迟确认算法
因特网无法确保数据传输中没有出错,TCP通过自身的机制来保证数据的正确传输:
- 发送的每个TCP段都有一个数据完整性的校验值,TCP的一端接收到IP分组信息后,检验成功会回送一个确认分组,如果在指定时间内没有收到确认分组,另一端会重新发送TCP段。
- 因为确认分组很小,所以TCP允许在回送的TCP段中捎带一份确认分组。
提高效率
延迟确认算法:
- 定义:为了提高确认分组找到同向的数据分组,会在一个特定的时间窗口内(100~200Ms),将确认分组放在缓冲池中,等同向的数据分组,如果在规定的时间内没有找到,将单独发送确认分组。
- 弊端:如果没有那么多同向的数据分组回传,这个时间窗口就会造成性能低下,可以禁止或调整这个特性。
TCP慢启动拥塞控制
TCP的连接速度会随着传输时间自我调整,当TCP成功建立的时候,会限制发送速度;TCP会发送一组数据分组,确认没有问题之后一次发送两组数据,两组数据没有问题会发送四组数据,直到到达上限,所以长时间保持连接传输的TCP连接要比刚开始建立的连接拥有更快的传输速率。
解决方案:重用现存连接,HTTP持久连接。
面试题:HTTP持久连接的原因:TCP建立的50%耗时、传输速率
数据聚集的Nagle 算法
Nagle算法的思想是,每个IP分组至少40个字节,如果要发送的TCP段数据很小,过多的小数据分组会降低TCP性能,所以主张将小的TCP段集合在一个IP分组中发送;
鼓励发送全尺寸的段,因特网上一般是几百字节,如果TCP已经发送了一个全尺寸的段,剩下的数据有两种方式:
- 等待上次发送的段确认分组到达之后发送
- 等到填满了一个全尺寸的段再发送。
弊端:
- 小的HTTP报文可能无法填满一个全尺寸段,这个时间窗口会造成延迟
- 在等待上个数据的确认分组的时候,本身就存在延迟确认的时间窗口(100~200ms)
禁用Nagle算法的设置参数是TCP_NODELAY
,但要确保你发送的数据都是大尺寸的。
TIME_WAIT 时延和端口耗尽
- 当某个TCP端点关闭TCP连接的时候,会在内存中维持一个控制块的,用来记录最近连接的IP地址和端口号
- 会维护一段时间,大概是两分钟(最大分段使用期的两倍),以前路由器速度很慢的时候,预估一个分组信息在因特网丢弃之前,它最多可以保存一分钟
- 目的是防止两分钟内重新创建了相同地址端口的连接,A端发送给B端的分组信息,因为没有过期,并且是相同的TCP连接,导致数据被重复发送,破坏TCP数据。
实际场景:
- HTTP服务器在80端口上进行监听,根据格式
<source-IP, source-Port , des-IP , 80>
,地址是固定的,只有 source-Port是可以改变的 - 客户端每次连接,为了连接的唯一性,都会获取一个端口号,假设source主机端口号只有60000个, 那么每秒的连接数就被限制在 60000/120=500个
HTTP连接管理
Connection首部:指定了连接的一些元数据;HTTP应用程序在接到带有Connection首部的报文时,会解析这些值并应用,然后在转发到下一个应用程序之前会删除Connection信息。
提高HTTP性能的几种方式:
- 并行连接:多个TCP连接发起并行的HTTP请求
- 持久连接:重用连接,消除TCP创建关闭时延 + 提高传输速率
- 管道化连接:通过共享的TCP连接发起并行的HTTP请求
并行连接
弊端:
客户端的速率限制,导致连接发生竞争条件。
过多的并发请求消耗很多内存资源,导致客户端卡顿和服务器的压力陡增
所以Agent代理一般的并发数量会控制在4个左右
每个事务都会新建一个连接,会耗费时间和宽带
每次创建的连接速度一开始会被限制,每条的性能都有所降低
持久连接+并行连接 是最高效的方式:打开少量的并行连接,每条都是持久连接。
持久连接:在事务处理结束后将TCP连接保持在打开状态,以便为未来的HTTP请求重用现存的连接
- HTTP/1.0 + “keep-alive”
- HTTP/1.1 “persistent” 连接
并行事务