不过如果web服务器并且开启了keep-alive的话,当达到超时时长服务器也会主动关闭。(我这里并不是说TCP/IP详解错了,而是它在那一节主要是针对TCP来说,并没有引入HTTP,而且它说的是通常而不是一定)
我使用Nginx做测试,并且在配置文件中设置了keepalive_timeout 65s;
,Nginx的默认设置是75s,设置为0表示禁用keepalive,如下图:
下面我使用Chrom浏览器访问这个Nginx默认提供的主页,并通过抓包程序来监控整个通信过程,如下图:
从上图可以看出来在有效数据传送完毕后,中间出现了Keep-Alive标记的通信,并且在65秒内没有请求后服务器主动断开连接,这种情况你在Nginx的服务器上就会看到TIME_WAIT的状态。
有人说Nginx监听80或者443,客户端都是连接这个端口,服务端怎么会端口耗尽呢?就像下图一样(忽略图中的TIME_WAIT,产生这个的原因上面已经说过了是因为Nginx的keepalive_timeout设置导致的)
其实,这取决于Nginx工作模式,我们使用Nginx通常都是让其工作在代理模式,这就意味着真正的资源或者数据在后端Web应用程序上,比如Tomcat。代理模式的特点是代理服务器代替用户去后端获取数据,那么此时相对于后端服务器来说,Nginx就是一个客户端,这时候Nginx就会使用随机端口来向后端发起请求,而系统可用随机端口范围是一定的,可以使用sysctl net.ipv4.ip_local_port_range
命令来查看服务器上的随机端口范围。
通过我们之前介绍的延迟确认、Nagle算法以及代理模式下Nginx充当后端的客户端角色并使用随机端口连接后端,这就意味着服务端的端口耗尽风险是存在的。随机端口释放速度如果比与后端建立连接的速度慢就有可能出现。不过一般不会出现这个情况,至少我们公司的Nginx我没有发现有这种现象产生。因为首先是静态资源都在CDN上;其次后端大部分都是REST接口提供用户认证或者数据库操作,这些操作其实后端如果没有瓶颈的话基本都很快。不过话说回来如果后端真的有瓶颈且扩容或者改架构成本比较高的话,那么当面对大量并发的时候你应该做的是限流防止后端被打死。
我们说过HTTP通信依赖TCP连接,一个TCP连接就是一个套接字,对于类Unix系统来说,打开一个套接字就是打开一个文件,如果有100个请求连接服务端,那么一旦连接建立成功服务端就会打开100个文件,而Linux系统中一个进程可以打开的文件数量是有限的ulimit -f
,所以如果这个数值设置的太小那么也会影响HTTP连接。而对以代理模式运行的Nginx或者其他HTTP程序来说,通常一个连接它就要打开2个套接字也就会占用2个文件(命中Nginx本地缓存或者Nginx直接返回数据的除外)。所以对于代理服务器这个进程可打开的文件数量也要设置的大一点。
首先我们要知道keepalive可以设置在2个层面上,且2个层面意义不同。TCP的keepalive是一种探活机制,比如我们常说的心跳信息,表示对方还在线,而这种心跳信息的发送由有时间间隔的,这就意味着彼此的TCP连接要始终保持打开状态;而HTTP中的keep-alive是一种复用TCP连接的机制,避免频繁建立TCP连接。所以一定明白TCP的Keepalive和HTTP的Keep-alive不是一回事。
非持久连接会在每个HTTP事务完成后断开TCP连接,下一个HTTP事务则会再重新建立TCP连接,这显然不是一种高效机制,所以在HTTP/1.1以及HTTP/1.0的增强版本中允许HTTP在事务结束后将TCP连接保持打开状态,以便后续的HTTP事务可以复用这个连接,直到客户端或者服务器主动关闭该连接。持久连接减少了TCP连接建立的次数同时也最大化的规避了TCP慢启动带来的流量限制。
相关教程:HTTP视频教程
再来看一下这张图,图中的keepalive_timeout 65s
设置了开启http的keep-alive特性并且设置了超时时长为65秒,其实还有比较重要的选项是keepalive_requests 100;
它表示同一个TCP连接最多可以发起多少个HTTP请求,默认是100个。
在HTTP/1.0中keep-alive并不是默认使用的,客户端发送HTTP请求时必须带有Connection: Keep-alive
的首部来试图激活keep-alive,如果服务器不支持那么将无法使用,所有请求将以常规形式进行,如果服务器支持那么在响应头中也会包括Connection: Keep-alive
的信息。
在HTTP/1.1中默认就使用Keep-alive,除非特别说明,否则所有连接都是持久的。如果要在一个事务结束后关闭连接,那么HTTP的响应头中必须包含Connection: CLose
首部,否则该连接会始终保持打开状态,当然也不能总是打开,也必须关闭空闲连接,就像上面Nginx的设置一样最多保持65秒的空闲连接,超过后服务端将会主动断开该连接。
在Linux上没有一个统一的开关去开启或者关闭TCP的Keepalive功能,查看系统keepalive的设置sysctl -a | grep tcp_keepalive
,如果你没有修改过,那么在Centos系统上它会显示:
net.ipv4.tcp_keepalive_intvl = 75 # 两次探测直接间隔多少秒 net.ipv4.tcp_keepalive_probes = 9 # 探测频率 net.ipv4.tcp_keepalive_time = 7200 # 表示多长时间进行一次探测,单位秒,这里也就是2小时
按照默认设置,那么上面的整体含义就是2小时探测一次,如果第一次探测失败,那么过75秒再探测一次,如果9次都失败就主动断开连接。
如何开启Nginx上的TCP层面的Keepalive,在Nginx中有一个语句叫做listen
它是server段里面用于设置Nginx监听在哪个端口的语句,其实它后面还有其他参数就是用来设置套接字属性的,看下面几种设置:
# 表示开启,TCP的keepalive参数使用系统默认的 listen 80 default_server so_keepalive=on; # 表示显式关闭TCP的keepalive listen 80 default_server so_keepalive=off; # 表示开启,设置30分钟探测一次,探测间隔使用系统默认设置,总共探测10次,这里的设 # 置将会覆盖上面系统默认设置 listen 80 default_server so_keepalive=30m::10;
所以是否要在Nginx上设置这个so_keepalive,取决于特定场景,千万不要把TCP的keepalive和HTTP的keepalive搞混淆,因为Nginx不开启so_keepalive也不影响你的HTTP请求使用keep-alive特性。如果客户端和Nginx直接或者Nginx和后端服务器之间有负载均衡设备的话而且是响应和请求都会经过这个负载均衡设备,那么你就要注意这个so_keepalive了。比如在LVS的直接路由模式下就不受影响,因为响应不经过
LVS,不过要是NAT模式就需要留意,因为LVS保持TCP会话也有一个时长,如果该时长小于后端返回数据的时长那么LVS就会在客户端还没有收到数据的情况下断开这条TCP连接。
TCP拥塞控制有一些算法,其中就包括TCP慢启动、拥塞避免等算法?
有些地方也叫做IP分片但都是一个意思,至于为什么分片简单来说就是受限于数据链路层,不同的数据链路其MTU不同,以太网的是1500字节,在某些场景会是1492字节;FDDI的MTU又是另外一种大小,单纯考虑IP层那么IP数据包最大是65535字节?
在《HTTP权威指南》P90页中并没有说的特别清楚,这种情况是相对于客户端来说还是服务端,因为很有可能让人误解,当然并不是说服务端不会出现端口耗尽的情况,所以我这里才增加了2项内容?
最长不会超过2分钟?
相关教程:HTTP视频教程
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com