`

HTTP Keep-Alive是什么?如何工作?

阅读更多

 

HTTP Keep-Alive

在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。

使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减 少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内 核调用,socket的accept()和close()调用)。

但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。

 

keepalvie 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连接。

 

下面写一个脚本,方便测试:

sleep(60);	//为了便于分析测试,会根据测试进行调整
echo "www.example.com";

 

1. 当keepalive_timeout时间为0时,即不启用Keep-Alive时,一个tcp连接的生命周期:

#tcpdump -n host 218.1.57.236 and port 80
20:36:50.792731 IP 218.1.57.236.43052 > 222.73.211.215.http: S 1520902589:1520902589(0) win 65535
20:36:50.792798 IP 222.73.211.215.http > 218.1.57.236.43052: S 290378256:290378256(0) ack 1520902590 win 5840
20:36:50.801629 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 1 win 32768

20:36:50.801838 IP 218.1.57.236.43052 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768
20:36:50.801843 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 797 win 59

20:37:50.803230 IP 222.73.211.215.http > 218.1.57.236.43052: P 1:287(286) ack 797 win 59
20:37:50.803289 IP 222.73.211.215.http > 218.1.57.236.43052: F 287:287(0) ack 797 win 59
20:37:50.893396 IP 218.1.57.236.43052 > 222.73.211.215.http: . ack 288 win 32625
20:37:50.894249 IP 218.1.57.236.43052 > 222.73.211.215.http: F 797:797(0) ack 288 win 32625
20:37:50.894252 IP 222.73.211.215.http > 218.1.57.236.43052: . ack 798 win 59
  • 第1~3行建立tcp三次握手,建立连接。用时8898μs
  • 第4~5行通过建立的连接发送第一个http请求,服务端确认收到请求。用时5μs
  • 第5~6行,可以知道脚本执行用时60s1387μs,与php脚本相符。
  • 第6、8行服务端发送http响应。发送响应用时90166μs。
  • 第7行,表明由服务端守护进程主动关闭连接。结合第6、8行,说明http响应一旦发送完毕,服务端马上关闭这个tcp连接
  • 第7、9、10说明tcp连接顺序关闭,用时90963μs。需要注意,这里socket资源并没有立即释放,需要等待2MSL时间(60s)后才被真正释放。

由此可见,在没有设置 keepalive_timeout 情况下,一个socket资源从建立到真正释放需要经过的时间是:建立tcp连接 + 传送http请求 + php脚本执行 + 传送http响应 + 关闭tcp连接 + 2MSL 。(注:这里的时间只能做参考,具体的时间主要由网络带宽,和响应大小而定)

 

2. 当keepalive_timeout时间大于0时,即启用Keep-Alive时,一个tcp连接的生命周期。为了便于分析,我们将keepalive_timeout设置为300s

 

#tcpdump -n host 218.1.57.236 and port 80
21:38:05.471129 IP 218.1.57.236.54049 > 222.73.211.215.http: S 1669618600:1669618600(0) win 65535
21:38:05.471140 IP 222.73.211.215.http > 218.1.57.236.54049: S 4166993862:4166993862(0) ack 1669618601 win 5840
21:38:05.481731 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 1 win 32768
21:38:05.481976 IP 218.1.57.236.54049 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768
21:38:05.481985 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 797 win 59

21:38:07.483626 IP 222.73.211.215.http > 218.1.57.236.54049: P 1:326(325) ack 797 win 59
21:38:07.747614 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 326 win 32605
21:43:07.448454 IP 222.73.211.215.http > 218.1.57.236.54049: F 326:326(0) ack 797 win 59
21:43:07.560316 IP 218.1.57.236.54049 > 222.73.211.215.http: . ack 327 win 32605
21:43:11.759102 IP 218.1.57.236.54049 > 222.73.211.215.http: F 797:797(0) ack 327 win 32605
21:43:11.759111 IP 222.73.211.215.http > 218.1.57.236.54049: . ack 798 win 59
  • 我们先看一下,第6~8行,跟上次示例不一样的是,服务端httpd守护进程发完响应后,没有立即主动关闭tcp连接。
  • 第8行,结合第6行,我们可以看到,5分钟(300s)后,服务端主动关闭这个tcp连接。这个时间,正是我们设置的keepalive_timeout的时间。
  • 由此可见,设置了keepalive_timout时间情况下,一个socket建立到释放需要的时间是多了keepalive_timeout时间。

3. 当keepalive_timeout时间大于0,并且在同一个tcp连接发送多个http响应。这里为了便于分析,我们将keepalive_timeout设置为180s

通过这个测试,我们想弄清楚,keepalive_timeout是从第一个响应结束开启计时,还是最后一个响应结束开启计时。测试结果证实是后者,这里,我们每隔120s发一次请求,通过一个tcp连接发送了3个请求。

 

# tcpdump -n host 218.1.57.236 and port 80
22:43:57.102448 IP 218.1.57.236.49955 > 222.73.211.215.http: S 4009392741:4009392741(0) win 65535
22:43:57.102527 IP 222.73.211.215.http > 218.1.57.236.49955: S 4036426778:4036426778(0) ack 4009392742 win 5840
22:43:57.111337 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1 win 32768

22:43:57.111522 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1:797(796) ack 1 win 32768
22:43:57.111530 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 797 win 59
22:43:59.114663 IP 222.73.211.215.http > 218.1.57.236.49955: P 1:326(325) ack 797 win 59
22:43:59.350143 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 326 win 32605

22:45:59.226102 IP 218.1.57.236.49955 > 222.73.211.215.http: P 1593:2389(796) ack 650 win 32443
22:45:59.226109 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 2389 win 83
22:46:01.227187 IP 222.73.211.215.http > 218.1.57.236.49955: P 650:974(324) ack 2389 win 83
22:46:01.450364 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 974 win 32281

22:47:57.377707 IP 218.1.57.236.49955 > 222.73.211.215.http: P 3185:3981(796) ack 1298 win 32119
22:47:57.377714 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3981 win 108
22:47:59.379496 IP 222.73.211.215.http > 218.1.57.236.49955: P 1298:1622(324) ack 3981 win 108
22:47:59.628964 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1622 win 32768

22:50:59.358537 IP 222.73.211.215.http > 218.1.57.236.49955: F 1622:1622(0) ack 3981 win 108
22:50:59.367911 IP 218.1.57.236.49955 > 222.73.211.215.http: . ack 1623 win 32768
22:50:59.686527 IP 218.1.57.236.49955 > 222.73.211.215.http: F 3981:3981(0) ack 1623 win 32768
22:50:59.686531 IP 222.73.211.215.http > 218.1.57.236.49955: . ack 3982 win 108
  • 第一组,三个ip包表示tcp三次握手建立连接,由浏览器建立。
  • 第二组,发送第一次http请求并且得到响应,服务端守护进程输出响应之后,并没马上主动关闭tcp连接。而是启动keepalive_timout计时。
  • 第三组,2分钟后,发送第二次http请求并且得到响应,同样服务端守护进程也没有马上主动关闭tcp连接,重新启动keepalive_timout计时。
  • 第四组,又2分钟后,发送了第三次http请求并且得到响应。服务器守护进程依然没有主动关地闭tcp连接(距第一次http响应有4分钟了,大于keepalive_timeout值),而是重新启动了keepalive_timout计时。
  • 第五组,跟最后一个响应keepalive_timeout(180s)内,守护进程再没有收到请求。计时结束,服务端守护进程主动关闭连接。4次挥手后,服务端进入TIME_WAIT状态。

这说明,当设定了keepalive_timeout,一个socket由建立到释放,需要时间是:tcp建立 + (最后一个响应时间 – 第一个请求时间) + tcp关闭 + 2MSL。红色加粗表示每一次请求发送时间、每一次请求脚本执行时间、每一次响应发送时间,还有两两请求相隔时间。进一步测试,正在关闭或者 TIME_WAIT状态的tcp连接,不能传输http请求和响应。即,当一个连接结束keepalive_timeout计时,服务端守护进程发送第一 个FIN标志ip包后,该连接不能再使用了。

http keep-alive与tcp keep-alive

http keep-alive与tcp keep-alive,不是同一回事,意图不一样。http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。tcp keep-alive保鲜定时器,支持三个系统内核配置参数:

 

echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl
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连接。一般不会出现这种情况, 除非你需要这样做。

 

keep-alive与TIME_WAIT

使用http keep-alvie,可以减少服务端TIME_WAIT数量(因为由服务端httpd守护进程主动关闭连接)。道理很简单,相较而言,启用keep-alive,建立的tcp连接更少了,自然要被关闭的tcp连接也相应更少了。

最后

我想用一张示意图片来说明使用启用keepalive的不同。另外,http keepalive是客户端浏览器与服务端httpd守护进程协作的结果,所以,我们另外安排篇幅介绍不同浏览器的各种情况对keepalive的利用。

分享到:
评论

相关推荐

    Nextjs-keep-alive-demo.rar

    Nextjs-keep-alive 实现,vue中有这个专门的keep-alive插件,但是react没有,更别提nextjs了,这是现成的项目demo。 next9,10,11,12,13,14 及以上都可以用。直接使用或者移植到你的项目,非常方便。集成了发送...

    vue中keep-alive,include的缓存问题

    在Vue.js框架中,`keep-alive`是一个非常实用的内置组件,它能够对组件状态进行缓存,防止在切换路由时进行重复的渲染,提高性能。然而,在使用`keep-alive`组件的`include`属性时,可能会出现一些缓存问题。`...

    利用Keep-Alive处理Socket网络异常断开的方法

    TCP Keep-Alive的工作原理如下: 1. **触发条件**:当TCP连接在一定时间内(默认为2小时)没有数据传输时,会自动触发Keep-Alive机制。 2. **探测报文**:TCP协议会发送一个特殊的Keep-Alive数据包给对方,这个...

    HTTP协议Keep-Alive模式详解

    一、什么是 Keep-Alive 模式 Keep-Alive 模式是 HTTP 协议中的一种机制,它使客户端到服务器端的连接保持有效,从而避免了每个请求和应答都新建一个连接,并立即断开连接。Keep-Alive 模式使得客户端和服务器端可以...

    彻底揭秘keep-alive原理(小结)

    2.1 keep-alive是什么 keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。 2.2 一个场景 用户在某

    vue keep-alive请求数据的方法示例

    Vue Keep-Alive 请求数据的方法示例 Vue Keep-Alive 是 Vue 框架中的一个功能强大且实用的机制,可以缓存组件的状态,减少不必要的组件重渲染,提高应用程序的性能。但是,在使用 Keep-Alive 时,可能会遇到一些...

    keep-alive.7z

    在IT行业中,`keep-alive` 是一个非常重要的概念,特别是在前端开发领域,尤其是在使用Vue.js框架时...通过下载并分析“keep-alive.7z”压缩包中的文件,开发者可以深入理解其工作原理,并学会在自己的项目中灵活运用。

    keep-alive的介绍及使用

    如果需要频繁切换路由,这个时候就可以考虑用keep-alive了,来达到避免数据的重复请求的目的 keep-alive用来缓存组件,避免多次加载相应的组件,减少性能消耗。 简单一点来说就是从页面A链接到其他页面后回退到页面A...

    vue.js内置组件之keep-alive组件使用

    `keep-alive`是Vue.js框架中的一个内置组件,用于实现组件的缓存功能,避免在切换组件时销毁和重新创建实例,从而提高性能并保持组件的状态。在使用`keep-alive`时,它会包裹动态组件,并在不活动时缓存组件实例。 ...

    vue使用keep-alive切换页面,2种方法实现页面保持滚动位置.zip

    为了解决这个问题,Vue提供了一个名为`keep-alive`的组件,它可以缓存组件的状态,使得在页面切换后仍然能保留之前的滚动位置。下面我们将详细探讨两种使用`keep-alive`在Vue中实现页面保持滚动位置的方法。 首先,...

    umi-plugin-keep-alive:用于基于React激活的umijs

    umi-plugin-keep-alive 中文说明 | 此 <KeepAlive> 功能基于 在线示例 umi 多 tabs 示例: 使用方法 安装 npm install umi-plugin-keep-alive --save # or yarn add umi-plugin-keep-alive 从 umi 中导出 KeepAlive...

    vue组件 keep-alive 和 transition 使用详解

    1.keep-alive 能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似, 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件...

    深入理解与使用keep-alive(配合router-view缓存整个路由页面)

    《深入理解与使用keep-alive缓存路由页面》 在Vue.js开发中,有时我们需要保持组件的状态,避免在页面切换时重新渲染,提高用户体验。这时,`<keep-alive>`组件就显得尤为重要。本文将详细介绍如何配合`router-view...

    vue keep-alive 动态删除组件缓存的例子

    首先,什么是Vue中的keep-alive组件呢?keep-alive是Vue提供的一个抽象组件,它主要用于缓存动态组件,避免组件切换过程中导致的重新渲染,从而提高性能和用户体验。在页面切换时,被keep-alive包裹的组件会被缓存...

    Vue中keep-alive组件的深入理解

    本文将深入探讨`keep-alive`组件的工作原理及其在实际开发中可能遇到的问题及解决方案。 在Vue项目中,组件间的跳转通常通过路由进行。然而,当用户从A路由跳转到B路由,再从B路由跳转到C路由,然后返回B路由时,...

    keep-alive不能缓存多层级路由菜单问题解决

    这个组件的作用是在没有具体组件的情况下作为一个占位符,以便`keep-alive`仍然能够正常工作。在实际的`EmptyTemplate`组件中,我们可以包含一个`<router-view>`,这样即使在没有直接指定组件的情况下,依然可以显示...

    vue中进入详情页记住滚动位置的方法(keep-alive)

    本文将介绍如何通过使用Vue的内置组件keep-alive来实现进入详情页时记住滚动位置的方法。 首先,了解keep-alive组件的基本作用是必要的。keep-alive是Vue提供的一个抽象组件,它用来缓存不活动的组件实例,而不是...

    vue中keep-alive内置组件缓存的实例代码

    将要缓存的组件使用 keep-alive 包裹住即可。 keep-alive优点的介绍: 1. 切换组件时,当前组件不会触发销毁的生命周期钩子。也就是说不会销毁了。 2. 切换回来时,也不会重新创建。(既然都没有被销毁,哪里来的...

    Vue keep-alive组件页面缓存控制示例

    在Vue中,`<keep-alive>`组件是一个特殊的组件,用于缓存子组件的状态,防止页面在切换时重新渲染,从而提高用户体验。本示例主要探讨如何使用`<keep-alive>`组件进行页面缓存控制。 `<keep-alive>`的基本用法是在...

    vue中keep-alive组件的入门使用教程

    Vue.js中的`<keep-alive>`组件是一种非常实用的功能,用于在组件切换过程中保持组件的状态,避免每次切换都重新创建和销毁组件实例。这在处理需要维持数据或状态的复杂应用时尤其有用,例如音乐播放应用中保持播放...

Global site tag (gtag.js) - Google Analytics