在经过调试工具查看网络请求的时候,一般在response header能看到相似下面这种:Keep-Alive: timeout=10, max=94 。那么Keep-Alive究竟是什么呢?php
在http早期,每一个http请求都要求打开一个tpc socket链接,而且使用一次以后就断开这个tcp链接。nginx
使用keep-alive能够改善这种状态,即在一次TCP链接中能够持续发送多份数据而不会断开链接。经过使用keep-alive机制,能够减小tcp链接创建次数,也意味着能够减小TIME_WAIT状态链接,以此提升性能和提升httpd服务器的吞吐率(更少的tcp链接意味着更少的系统内核调用,socket的accept()和close()调用)。浏览器
可是,keep-alive并非免费的午饭,长时间的tcp链接容易致使系统资源无效占用。配置不当的keep-alive,有时比重复利用链接带来的损失还更大。因此,正确地设置keep-alive timeout时间很是重要。服务器
Httpd守护进程,通常都提供了keep-alive timeout时间设置参数。好比nginx的keepalive_timeout,和Apache的KeepAliveTimeout。这个keepalive_timout时间值意味着:一个http产生的tcp链接在传送完最后一个响应后,还须要hold住keepalive_timeout秒后,才开始关闭这个链接。网络
当httpd守护进程发送完一个响应后,理应立刻主动关闭相应的tcp链接,设置 keepalive_timeout后,httpd守护进程会想说:”再等等吧,看看浏览器还有没有请求过来”,这一等,即是keepalive_timeout时间。若是守护进程在这个等待的时间里,一直没有收到浏览发过来http请求,则关闭这个http链接。socket
下面写一个脚本,方便测试:tcp
1 sleep(60); //为了便于分析测试,会根据测试进行调整 2 echo "www.example.com";
1. 当keepalive_timeout时间为0时,即不启用Keep-Alive时,一个tcp链接的生命周期:工具
01 #tcpdump -n host 218.1.57.236 and port 80 02 20:36:50.792731 IP 218.1.57.236.43052 > 222.73.211.215.http: S 1520902589:1520902589(0) win 65535 03 20:36:50.792798 IP 222.73.211.215.http > 218.1.57.236.43052: S 290378256:290378256(0) ack 1520902590 win 5840 04 20:36:50.801629 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 1 win 32768 05 06 20:36:50.801838 IP 218.1.57.236.43052 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 07 20:36:50.801843 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 797 win 59 08 09 20:37:50.803230 IP 222.73.211.215.http > 218.1.57.236.43052: P 1:287(286) ack 797 win 59 10 20:37:50.803289 IP 222.73.211.215.http > 218.1.57.236.43052: F 287:287(0) ack 797 win 59 11 20:37:50.893396 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 288 win 32625 12 20:37:50.894249 IP 218.1.57.236.43052 > 222.73.211.215.http: F 797:797(0) ack 288 win 32625 13 20:37:50.894252 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 798 win 59
因而可知,在没有设置 keepalive_timeout 状况下,一个socket资源从创建到真正释放须要通过的时间是:创建tcp链接 + 传送http请求 + php脚本执行 + 传送http响应 + 关闭tcp链接 + 2MSL 。(注:这里的时间只能作参考,具体的时间主要由网络带宽,和响应大小而定)性能
2. 当keepalive_timeout时间大于0时,即启用Keep-Alive时,一个tcp链接的生命周期。为了便于分析,咱们将keepalive_timeout设置为300s测试
01 #tcpdump -n host 218.1.57.236 and port 80 02 21:38:05.471129 IP 218.1.57.236.54049 > 222.73.211.215.http: S 1669618600:1669618600(0) win 65535 03 21:38:05.471140 IP 222.73.211.215.http > 218.1.57.236.54049: S 4166993862:4166993862(0) ack 1669618601 win 5840 04 21:38:05.481731 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 1 win 32768 05 21:38:05.481976 IP 218.1.57.236.54049 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 06 21:38:05.481985 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 797 win 59 07 08 21:38:07.483626 IP 222.73.211.215.http > 218.1.57.236.54049: P 1:326(325) ack 797 win 59 09 21:38:07.747614 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 326 win 32605 10 21:43:07.448454 IP 222.73.211.215.http > 218.1.57.236.54049: F 326:326(0) ack 797 win 59 11 21:43:07.560316 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 327 win 32605 12 21:43:11.759102 IP 218.1.57.236.54049 > 222.73.211.215.http: F 797:797(0) ack 327 win 32605 13 21:43:11.759111 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 798 win 59
3. 当keepalive_timeout时间大于0,而且在同一个tcp链接发送多个http响应。这里为了便于分析,咱们将keepalive_timeout设置为180s
经过这个测试,咱们想弄清楚,keepalive_timeout是从第一个响应结束开启计时,仍是最后一个响应结束开启计时。测试结果证明是后者,这里,咱们每隔120s发一次请求,经过一个tcp链接发送了3个请求。
01 # tcpdump -n host 218.1.57.236 and port 80 02 22:43:57.102448 IP 218.1.57.236.49955 > 222.73.211.215.http: S 4009392741:4009392741(0) win 65535 03 22:43:57.102527 IP 222.73.211.215.http > 218.1.57.236.49955: S 4036426778:4036426778(0) ack 4009392742 win 5840 04 22:43:57.111337 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1 win 32768 05 06 22:43:57.111522 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768 07 22:43:57.111530 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 797 win 59 08 22:43:59.114663 IP 222.73.211.215.http > 218.1.57.236.49955: P 1:326(325) ack 797 win 59 09 22:43:59.350143 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 326 win 32605 10 11 22:45:59.226102 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1593:2389(796) ack 650 win 32443 12 22:45:59.226109 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 2389 win 83 13 22:46:01.227187 IP 222.73.211.215.http > 218.1.57.236.49955: P 650:974(324) ack 2389 win 83 14 22:46:01.450364 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 974 win 32281 15 16 22:47:57.377707 IP 218.1.57.236.49955 > 222.73.211.215.http: P 3185:3981(796) ack 1298 win 32119 17 22:47:57.377714 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3981 win 108 18 22:47:59.379496 IP 222.73.211.215.http > 218.1.57.236.49955: P 1298:1622(324) ack 3981 win 108 19 22:47:59.628964 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1622 win 32768 20 21 22:50:59.358537 IP 222.73.211.215.http > 218.1.57.236.49955: F 1622:1622(0) ack 3981 win 108 22 22:50:59.367911 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1623 win 32768 23 22:50:59.686527 IP 218.1.57.236.49955 > 222.73.211.215.http: F 3981:3981(0) ack 1623 win 32768 24 22:50:59.686531 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3982 win 108
这说明,当设定了keepalive_timeout,一个socket由创建到释放,须要时间是:tcp创建 + (最后一个响应时间 – 第一个请求时间) + tcp关闭 + 2MSL。红色加粗表示每一次请求发送时间、每一次请求脚本执行时间、每一次响应发送时间,还有两两请求相隔时间。进一步测试,正在关闭或者TIME_WAIT状态的tcp链接,不能传输http请求和响应。即,当一个链接结束keepalive_timeout计时,服务端守护进程发送第一个FIN标志ip包后,该链接不能再使用了。
http keep-alive与tcp keep-alive,不是同一回事,意图不同。http keep-alive是为了让tcp活得更久一点,以便在同一个链接上传送多个http,提升socket的效率。而tcp keep-alive是TCP的一种检测TCP链接情况的保鲜机制。tcp keep-alive保鲜定时器,支持三个系统内核配置参数:
1 echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time 2 echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl 3 echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes
keepalive是TCP保鲜定时器,当网络两端创建了TCP链接以后,闲置idle(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,来判断TCP链接情况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。若是没有收到对方的回答(ack包),则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对对方的ack,若是一直没有收到对方的ack,一共会尝试 tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。若是尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP链接。TCP链接默认闲置时间是2小时,通常设置为30分钟足够了。
也就是说,仅当nginx的keepalive_timeout值设置高于tcp_keepalive_time,而且距此tcp链接传输的最后一个http响应,通过了tcp_keepalive_time时间以后,操做系统才会发送侦测包来决定是否要丢弃这个TCP链接。通常不会出现这种状况,除非你须要这样作。
使用http keep-alvie,能够减小服务端TIME_WAIT数量(由于由服务端httpd守护进程主动关闭链接)。道理很简单,相较而言,启用keep-alive,创建的tcp链接更少了,天然要被关闭的tcp链接也相应更少了。
我想用一张示意图片来讲明使用启用keepalive的不一样。另外,http keepalive是客户端浏览器与服务端httpd守护进程协做的结果,因此,咱们另外安排篇幅介绍不一样浏览器的各类状况对keepalive的利用。
故名思意,Conent-Length表示实体内容长度,客户端(服务器)能够根据这个值来判断数据是否接收完成。可是若是消息中没有Conent-Length,那该如何来判断呢?又在什么状况下会没有Conent-Length呢?请继续往下看……