IT技术互动交流平台

KeepAlive详解

作者:HavenShen  来源:IT165收集  发布日期:2014-07-17 22:33:57

KeepAlive既熟悉又陌生,踩过坑的同学都知道痛。一线运维工程师踩坑之后对于KeepAlive的总结,你不应该错过!

最近工作中遇到一个问题,想把它记录下来,场景是这样的:

从上图可以看出,用户通过Client访问的是LVS的VIP, VIP后端挂载的RealServer是Nginx服务器。 Client可以是浏览器也可以是一个客户端程序。一般情况下,这种架构不会出现问题,但是如果Client端把请求发送给Nginx,Nginx的后端需要一段时间才能返回结果,超过1分30秒就会有问题,使用LVS作为负载均衡设备看到的现象就是1分30秒之后, Client和Nginx链接被断开,没有数据返回。

原因是LVS默认保持TCP的Session为90s,超过90s没有TCP报文在链接上传输,LVS就会给两端发送RESET报文断开链接。LVS这么做的原因相信大家都知道一二,我所炸ky"http://www.it165.net/qq/" target="_blank" class="keylink">qq1wLXE1K3S8tb30qrT0MG9teOjujwvcD4KCjxwPjEuIL3ayqG4utTYvvm64snosbjXytS0o6zDv9K7uPZUQ1AvVURQtcTBtL3Ttry74dTauLrU2L75uuLJ6LG4yc+0tL2o0ru49lNlc3Npb261xL3hubmjrCDBtL3TyOe5+9K71rGyu7bPv6qjrNXi1tZTZXNzaW9uveG5udDFz6LX7tbVu+HP+7rEtfTL+dPQtcTXytS0o6zL+dLUsdjQ68rNt8W19KGjPC9wPgoKPHA+Mi7B7c3iys23xbX0xNyxo7ukuvO2y7XE18rUtKOsyOe5+7mlu/fV382ouf2/1cG0vdOjrMG0vdO1vU5naW54yc+jrMjnuftOZ2lueMO709DX9rrPysogtcSxo7uko6xOZ2lueLvh0vLOqsG0vdPK/bn9tuC2+M7et6jM4bmpt/7O8aGjPC9wPgoKPHA+1eLW1s7KzOKyu9a7ysfU2kxWU8nP09CjrNaux7DU2snM08O4utTYvvm64snosbhGNcnP0/a1vbn9zazR+bXEzsrM4qOsRjW1xHNlc3Npb262z7+qt73KvbrNTFZT09C148f4sfCjrEY1sru74db3tq+3osvNUkVTRVS4+MG0vdO1xMG9tsujrHNlc3Npb27P+8qn1q6686OstbHBtL3T1tDSu7e91Nm0zreiy82xqM7EyrG74b3TytW1vUY1tcRSRVNFVCwg1q6687XEz9bP88rH1Nm0zreiy82xqM7EtcTSu7bLVENQwbS909e0zKzS0b6tts+/qqOstvjB7c3i0ru2y8i0u7nKx0VTVEFCTElTSNe0zKyhozwvcD4KCjxwPtaqtcDKx7i61Ni++briyeixuNSt0vLWrrrzo6y12tK7t7TTpr7NysfNqLn9v6rG9EtlZXBBbGl2ZcC0veK+9qGjtb20y9XiuPbOyszi06a4w8rHveHK+MHLo6y1q8rHztK3os/Wuf3Su7bOyrG85Nfc09bT0MjLzOHG8EtlZXBBbGl2ZbXEzsrM4qOsyfXWwbeiz9bTydPaS2VlcEFsaXZltcTA7b3isrvV/ci3wMu30cHLuty24NfK1LSjrNStsb7E3Mq508NMVlO1xNOm08O3xdTawcu5q834z8Kzwcf4o6y78tXfu7uzycHLyczTw0Y1yeixuChGNcnosbi1xFNlc3Npb262z7+qyrG85NKqs6TSu7Xjo6zErMjP06a4w8rHNbfW1tMpoaM8L3A+Cgo8cD7L+dLUztK+9raosNHO0taqtcC1xEtlZXBBbGl2Zdaqyra149C0xqqyqb/Nt9bP7bP2wLShozwvcD4KCjxwPjxzdHJvbmc+zqrKssO00qrT0EtlZXBBbGl2ZaO/PC9zdHJvbmc+PC9wPgoKPHA+1NrMuEtlZXBBbGl2Zdaux7CjrM7Sw8fPyMC0wcu94s/CvPK1pVRDUNaqyrYo1qrKtrrcvPK1paOsuN/K1taxvdO69sLUKaGjytfPyNKqw/fIt7XEysfU2lRDULLjysfDu9PQJmxkcXVvO8frx/MmcmRxdW870rvLtbXEo6y+rbOjzP21vdTaVENQsuO3osvN0ru49sfrx/OjrNXi1tbLtbeoyse07c7ztcShozwvcD4KCjxwPlRDUMrH0rvW1s2o0MW1xLe9yr2jrCZsZHF1bzvH68fzJnJkcXVvO9K7tMrKx8rCzvHJz7XEuMXE7qOsSFRUUNCt0unKx9K71tbKws7x0K3S6aOsyOe5+8u1t6LLzdK7uPZIVFRQx+vH86Os1eLW1su1t6i+zcO709DOyszioaPSsr6ts6PM/bW9w+bK1LnZt7TAodPQ0KnD5srU1MvOrLXEzazRp6Osu/mxvrXEVENQyP20zs7Vyta1xLjFxO6yu8fls/6jrMPmytS52c7KVENQysfI57rOvajBosG0vdOjrMPmytTV38nPwLS+zcu1o6y82cjnztLKx7/Nu6e2y87St6LLzdK7uPbH68fzuPi3/s7xtsujrLf+zvG2y7eiy83Su7j2x+vH87j4ztKho6GjoaM8L3A+Cgo8cD7V4tbW0rvM/b7N1qq1wLbUVENQu/mxvrjFxO6yu8fls/6ho8/Cw+bKx87Szai5/XdpcmVzaGFya9elyKG1xNK7uPZUQ1C9qMGiztXK1rXEuf2zzKGjo6jD/MHu0NC7+bG+yc/Tw1RDUGR1bXAsuvPD5s7Sw8e7ubvh08PV4tXFzbzLtcP3zsrM4qOpOjwvcD4KPHA+PGltZyBzcmM9"http://www.it165.net/uploadfile/files/2014/0717/20140717203758112.jpg" alt="" />

现在我看只要看前3行,这就是TCP三次握手的完整建立过程,第一个报文SYN从发起方发出,第二个报文SYN,ACK是从被连接方发出,第三个报文ACK确认对方的SYN,ACK已经收到,如下图:

但是数据实际上并没有传输,请求是有数据的,第四个报文才是数据传输开始的过程,细心的读者应该能够发现wireshark把第四个报文解析成HTTP协议,HTTP协议的GET方法和URI也解析出来,所以说TCP层是没有请求的概念,HTTP协议是事务性协议才有请求的概念,TCP报文承载HTTP协议的请求(Request)和响应(Response)。

现在才是开始说明为什么要有KeepAlive。链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。

TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。

如何开启KeepAlive?

KeepAlive并不是默认开启的,在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。需要开启KeepAlive的应用必须在TCP的socket中单独开启。Linux Kernel有三个选项影响到KeepAlive的行为:


1.net.ipv4.tcpkeepaliveintvl = 75
2.net.ipv4.tcpkeepaliveprobes = 9
3.net.ipv4.tcpkeepalivetime = 7200


tcpkeepalivetime的单位是秒,表示TCP链接在多少秒之后没有数据报文传输启动探测报文; tcpkeepaliveintvl单位是也秒,表示前一个探测报文和后一个探测报文之间的时间间隔,tcpkeepaliveprobes表示探测的次数。

TCP socket也有三个选项和内核对应,通过setsockopt系统调用针对单独的socket进行设置:


TCPKEEPCNT: 覆盖 tcpkeepaliveprobes
TCPKEEPIDLE: 覆盖 tcpkeepalivetime
TCPKEEPINTVL: 覆盖 tcpkeepalive_intvl

举个例子,以我的系统默认设置为例,kernel默认设置的tcpkeepalivetime是7200s, 如果我在应用程序中针对socket开启了KeepAlive,然后设置的TCP_KEEPIDLE为60,那么TCP协议栈在发现TCP链接空闲了60s没有数据传输的时候就会发送第一个探测报文。

TCP KeepAlive和HTTP的Keep-Alive是一样的吗?

估计很多人乍看下这个问题才发现其实经常说的KeepAlive不是这么回事,实际上在没有特指是TCP还是HTTP层的KeepAlive,不能混为一谈。TCP的KeepAlive和HTTP的Keep-Alive是完全不同的概念。

TCP层的KeepAlive上面已经解释过了。 HTTP层的Keep-Alive是什么概念呢? 在讲述TCP链接建立的时候,我画了一张三次握手的示意图,TCP在建立链接之后, HTTP协议使用TCP传输HTTP协议的请求(Request)和响应(Response)数据,一次完整的HTTP事务如下图:

各位看官请注意,这张图我简化了HTTP(Req)和HTTP(Resp),实际上的请求和响应需要多个TCP报文。

从图中可以发现一个完整的HTTP事务,有链接的建立,请求的发送,响应接收,断开链接这四个过程,早期通过HTTP协议传输的数据以文本为主,一个请求可能就把所有要返回的数据取到,但是,现在要展现一张完整的页面需要很多个请求才能完成,如图片,JS,CSS等,如果每一个HTTP请求都需要新建并断开一个TCP,这个开销是完全没有必要的。

开启HTTP Keep-Alive之后,能复用已有的TCP链接,当前一个请求已经响应完毕,服务器端没有立即关闭TCP链接,而是等待一段时间接收浏览器端可能发送过来的第二个请求,通常浏览器在第一个请求返回之后会立即发送第二个请求,如果某一时刻只能有一个链接,同一个TCP链接处理的请求越多,开启KeepAlive能节省的TCP建立和关闭的消耗就越多。

当然通常会启用多个链接去从服务器器上请求资源,但是开启了Keep-Alive之后,仍然能加快资源的加载速度。HTTP/1.1之后默认开启Keep-Alive, 在HTTP的头域中增加Connection选项。当设置为Connection:keep-alive表示开启,设置为Connection:close表示关闭。实际上HTTP的KeepAlive写法是Keep-Alive,跟TCP的KeepAlive写法上也有不同。所以TCP KeepAlive和HTTP的Keep-Alive不是同一回事情。

Nginx的TCP KeepAlive如何设置?

开篇提到我最近遇到的问题,Client发送一个请求到Nginx服务端,服务端需要经过一段时间的计算才会返回, 时间超过了LVS Session保持的90s,在服务端使用Tcpdump抓包,本地通过wireshark分析显示的结果如第二副图所示,第5条报文和最后一条报文之间的时间戳大概差了90s。

在确定是LVS的Session保持时间到期的问题之后,我开始在寻找Nginx的TCP KeepAlive如何设置,最先找到的选项是keepalivetimeout,从同事那里得知keepalivetimeout的用法是当keepalivetimeout的值为0时表示关闭keepalive,当keepalivetimeout的值为一个正整数值时表示链接保持多少秒,于是把keepalivetimeout设置成75s,但是实际的测试结果表明并不生效。

显然keepalivetimeout不能解决TCP层面的KeepAlive问题,实际上Nginx涉及到keepalive的选项还不少,Nginx通常的使用方式如下:

从TCP层面Nginx不仅要和Client关心KeepAlive,而且还要和Upstream关心KeepAlive, 同时从HTTP协议层面,Nginx需要和Client关心Keep-Alive,如果Upstream使用的HTTP协议,还要关心和Upstream的Keep-Alive,总而言之,还比较复杂。

所以搞清楚TCP层的KeepAlive和HTTP的Keep-Alive之后,就不会对于Nginx的KeepAlive设置错。我当时解决这个问题时候不确定Nginx有配置TCP keepAlive的选项,于是我打开Ngnix的源代码,在源代码里面搜索TCP_KEEPIDLE,相关的代码如下:

从代码的上下文我发现TCP KeepAlive可以配置,所以我接着查找通过哪个选项配置,最后发现listen指令的so_keepalive选项能对TCP socket进行KeepAlive的配置。

以上三个参数只能使用一个,不能同时使用, 比如sokeepalive=on, sokeepalive=off或者sokeepalive=30s::(表示等待30s没有数据报文发送探测报文)。通过设置listen 80,sokeepalive=60s::之后成功解决Nginx在LVS保持长链接的问题,避免了使用其他高成本的方案。在商用负载设备上如果遇到类似的问题同样也可以通过这种方式解决。

延伸阅读:

Tag标签: KeepAlive详解  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规