TCP/IP KeepAlive

Posted yunxizhujing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP/IP KeepAlive相关的知识,希望对你有一定的参考价值。


TCP的keepalive

keepalive是设置在操作系统级别,作用于到本机的连接。在一定时间内对远程主机发送TCP探测报文用于探测对方是否存活。

 

技术分享图片

上图2个场景是最常见的,但是针对于keepalive的问题是一样的。无非就是客户端和最终的WEB服务器直接多了中间设备。这会怎么样呢?正常情况下不会有问题,但是客户端把请求发送给nginx,Nginx的后端Tomcat需要一定时间才能返回结果,超过90秒就会有问题,如果使用LVS做负载均衡看到的现象就是90秒内没有返回则LVS会把客户端到Nginx的连接断开。因为LVS默认保持的TCP会话为90秒。超过90秒没有TCP传输,LVS就会给客户端和Nginx发送RESET报文断开连接。这样做的原因其实就是节省资源关闭空闲连接和保护后端。遇到这种请求你只需要在LVS上开启keepalive就好,当然你的Nginx上也要设置,因为真正的后端服务器是Tomcat等应用程序。

keepalive是什么:

连接建立以后,如果应用程序或上层协议一直不发数据或者间隔很久才发一次,那么如何确定建立连接的双方还存在呢?在TCP协议的设计中,在一段时间之后,TCP自动发送一个空数据报文给对方,如果对方回应了这个报文说明还在线,那么继续保持连接,如果对方没有回应并且经过多次重试发送之后依然没有回应,则认为对方不在线可以关闭连接。

如何开启keepalive:

keepalive在Linux系统上没有一个全局开关来开启或关闭这个功能以为它是TCP的一个特性,所以不能简单的说默认是不是开启。因为开启这个功能是需要应用程序在注册使用socket时单独设置的,Linux上关于TCP的内核参数只是会影响keepalive的行为。注意:启动Nginx或者LVS等任何网络服务都会使用socket。

sysctl -a | grep net.ipv4.tcp_keepalive

技术分享图片

参数 含义
net.ipv4.tcp_keepalive_intvl 表示发送前一个探测报文和后一个探测报文的间隔时间
net.ipv4.tcp_keepalive_probes 表示探测次数,超过这个次数还是探测失败则关闭连接
net.ipv4.tcp_keepalive_time 表示TCP连接多少秒之后没有数据报文传输就启动探测报文

代码体现

setsockopt函数是设置与套接字有关的选项,它里面的选项有很多,下面的SO_KEEPALIVE表示长连接。

//使用长连接
if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
{
    //if error
}
 
//设置选项
if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1)
{
    //if error
}
 
if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1)
{
    //if error
}
 
if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1)
{
    //if error
}
socket选项 对应的内核参数
TCP_KEEPCNT net.ipv4.tcp_keepalive_probes
TCP_KEEPIDLE net.ipv4.tcp_keepalive_time
TCP_KEEPINTVL net.ipv4.tcp_keepalive_intvl

Linux系统对这三个参数有默认设置,你的应用程序可以覆盖自行设置需要的值。

HTTP的keep-alive

HTTP的keep-alive和TCP的不是一个概念,一个页面上有几百个元素一个元素其实就是一个HTTP请求,如果每个请求都打开和关闭一次TCP连接那相当消耗资源,对于HTTP的Keep-Alive来说就是TCP连接的复用,一个请求完毕后服务器不关闭连接而是等待一段时间接收浏览器可能发来的之后的请求。通常浏览器在完成第一个请求之后会马上发送第二个请求,所以这样会节省很多资源消耗。

Nginx如何开启TCP层的KeepAlive呢?

从TCP层面上Nginx要关系和client和后端upstream的KeepAlive,同时从HTTP层面Nginx还需要关系client和upstream的keep-alive。

参数 说明
so_keepalive

用于设置监听套接字的TCP KeepAlive行为,如果只是设置on而不设置具体参数则使用操作系统默认设置

on|off|[keepidle]:[keepintvl]:[keepcnt]

on表示开启 off表示关闭  keepidle表示等待时间   keepintvl表示探测报文发送间隔时间  keepcnt表示探测报文发送次数

以上参数只能用一个。该参数属于listen的辅助参数,在server端中,配置完监听端口可以使用这个参数。

listen 80 so_keepalive=on,如果要设置时间可以这样设置

listen 80 so_keepalive=30::10

在Nginx中针对TCP层的keepalive只有这一个。

Nginx如何开启针对前端客户端的HTTP层的keep-alive?

参数 说明
keepalive_timeout 0表示关闭keepalive,设置大于0的值表示保持链接多少秒,这个值不能解决TCP层面的KeepAlive问题
keepalive_requests 一个长连接建立之后,Nginx会给客户端计数,达到数值时则强制关闭连接,导致Nginx服务器出现TIME_WAIT。默认100,对于QPS比较高的场景这个值可以设置大一点。

Nginx如何开启针对后端服务器的HTTP层的keep-alive?

参数 说明
keepalive 这个是在upstream中设置的。设置upstream到后端服务器的最大空闲长连接数量,当达到数量时则收回,它并不影响到后端的并发数量。如果设置的值比较小对于不同时段的请求和响应数量均衡的场景没有影响,但是对于不同时段请求数量不同就有影响。所以建议设置大一点。这个的计算要和QPS和RT来计算出需要多少长连接数量,比如10000QPS,每个请求0.1秒。1/0.1=10, 10000/10=1000,也就是需要1000个长连接,不过通常可以设置到10%-30%。

总结

HTTP的keep-alive是为了让TCP连接存活久一点以便复用连接完成更多HTTP请求,提高连接利用率。

TCP的Keepalive是一种TCP连接的探测机制,使其一直保持可用。


以上是关于TCP/IP KeepAlive的主要内容,如果未能解决你的问题,请参考以下文章

闲说HeartBeat心跳包和TCP协议的KeepAlive机制

Android tcp/ip 读写缓冲区脱离主代码

如何在 Windows Server 2008 上设置 Keepalive

TCP/IP传输层协议实现 - TCP的保活定时器(lwip)

Tomcat高效响应的秘密 keep alive

Nginx四层负载均衡实践