`

KeepAlive详解

阅读更多

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

 

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

bubuko.com,布布扣

从上图可以看出,用户通过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这么做的原因相信大家都知道一二,我所知道的原因主要有两点:

 

1. 节省负载均衡设备资源,每一个TCP/UDP的链接都会在负载均衡设备上创建一个Session的结构, 链接如果一直不断开,这种Session结构信息最终会消耗掉所有的资源,所以必须释放掉。

 

2.另外释放掉能保护后端的资源,如果攻击者通过空链接,链接到Nginx上,如果Nginx没有做合适 的保护,Nginx会因为链接数过多而无法提供服务。

 

这种问题不只是在LVS上有,之前在商用负载均衡设备F5上遇到过同样的问题,F5的session断开方式和LVS有点区别,F5不会主动发送RESET给链接的两端,session消失之后,当链接中一方再次发送报文时会接收到F5的RESET, 之后的现象是再次发送报文的一端TCP链接状态已经断开,而另外一端却还是ESTABLISH状态。

 

知道是负载均衡设备原因之后,第一反应就是通过开启KeepAlive来解决。到此这个问题应该是结束了,但是我发现过一段时间总又有人提起KeepAlive的问题,甚至发现由于KeepAlive的理解不正确浪费了很多资源,原本能使用LVS的应用放在了公网下沉区,或者换成了商用F5设备(F5设备的Session断开时间要长一点,默认应该是5分钟)。

 

所以我决定把我知道的KeepAlive知识点写篇博客分享出来。

 

为什么要有KeepAlive?

 

在谈KeepAlive之前,我们先来了解下简单TCP知识(知识很简单,高手直接忽略)。首先要明确的是在TCP层是没有“请求”一说的,经常听到在TCP层发送一个请求,这种说法是错误的。

 

TCP是一种通信的方式,“请求”一词是事务上的概念,HTTP协议是一种事务协议,如果说发送一个HTTP请求,这种说法就没有问题。也经常听到面试官反馈有些面试运维的同学,基本的TCP三次握手的概念不清楚,面试官问TCP是如何建立链接,面试者上来就说,假如我是客户端我发送一个请求给服务端,服务端发送一个请求给我。。。

 

这种一听就知道对TCP基本概念不清楚。下面是我通过wireshark抓取的一个TCP建立握手的过程。(命令行基本上用TCPdump,后面我们还会用这张图说明问题):

bubuko.com,布布扣

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

bubuko.com,布布扣

但是数据实际上并没有传输,请求是有数据的,第四个报文才是数据传输开始的过程,细心的读者应该能够发现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事务如下图:

bubuko.com,布布扣

各位看官请注意,这张图我简化了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通常的使用方式如下:

bubuko.com,布布扣

从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,相关的代码如下:

bubuko.com,布布扣

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

bubuko.com,布布扣

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

分享到:
评论

相关推荐

    GRE隧道keepalive的说明

    ### GRE隧道Keepalive详解 #### 前言 随着网络技术的发展,GRE(Generic Routing Encapsulation)隧道作为一种广泛应用于互联网中的技术,对于实现不同网络之间的通信具有重要意义。然而,在实际应用过程中,如何...

    keepalive中文文档

    **Keepalive详解** `Keepalive`是网络通信中一个重要的概念,它主要用于维持TCP连接的活跃状态。在TCP协议中,一旦连接建立,双方就可以在连接上无限制地发送数据,直到一方主动关闭连接。然而,在长时间无数据传输...

    HTTP协议Keep-Alive模式详解

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

    springboot-keepalive设置测试

    对于keepalive,我们需要关注`keep-alive-timeout`属性,它设定了在服务器关闭空闲连接之前等待新请求的时间。 例如,我们可以在`application.properties`或`application.yml`文件中添加以下配置: ```properties ...

    【JavaScript源代码】vue keepAlive缓存清除问题案例详解.docx

    state.keepAlive = state.keepAlive.filter(p => p !== path); } } ``` ```html <keep-alive :include="store.state.keepAlive.join(',')"> ``` 这样,当需要缓存某个组件时,我们在Vuex中添加相应的路径;不...

    keepalive1.1.17.zip

    MySQL的主主复制结合Keepalive工具的使用详解 在分布式数据库系统中,数据的高可用性和一致性至关重要。MySQL的主主复制是一种常见的解决方案,它允许两个或多个服务器之间同步数据,确保任何一处的数据更改都会被...

    详解Nginx中HTTP的keepalive相关配置

    文章中还提到了通过脚本模拟长请求,使用tcpdump工具捕获TCP交互过程,以此来分析keepalive_timeout为0时的连接生命周期,观察到当keepalive_timeout设置为0时,服务器在完成一次请求的响应后,会立即关闭TCP连接,...

    keepalive的安装包

    《keepalive技术详解及其安装指南》 在计算机网络领域,Keepalive是一项重要的技术,它主要用于保持网络连接的活跃状态,防止因长时间无数据传输导致的连接超时或断开。Keepalive机制通常应用于TCP(传输控制协议)...

    centos7-lvs+keepalive部署

    ### CentOS 7 上 LVS+Keepalived 部署详解 #### 一、环境准备与软件安装 根据提供的部分内容可以看出,本教程旨在演示如何在 CentOS 7 系统上安装配置 LVS(Linux Virtual Server)及 Keepalived 服务,以实现...

    WDT.zip_WDIOC_KEEPALIVE_wdt

    《Linux平台下的看门狗驱动——WDIOC KEEPALIVE与WDT详解》 在嵌入式系统和服务器领域,看门狗定时器(Watchdog Timer, WDT)是一种至关重要的功能,它能确保系统的稳定性和可靠性。在Linux操作系统中,看门狗驱动...

    Netty空闲检测&Keepalive.pdf

    ### Netty空闲检测与Keepalive机制详解 #### 一、引言 在现代网络通信中,客户端与服务器之间的连接管理至关重要。为了确保连接的有效性和稳定性,Netty 提供了两种重要的机制:**空闲检测** 和 **Keepalive**。这...

    apache配置文件详解

    ### Apache配置文件详解 #### 一、Apache简介 Apache是一款开放源码的Web服务运行平台,在几乎所有常用的计算机操作系统中都有其身影,因其多平台、安全、稳定的特点而被广泛使用,成为当前最主流的Web服务器软件...

    setsockopt参数详解

    setsockopt参数详解 setsockopt 函数是 socket 编程中一个非常重要的函数,它允许开发者控制套接字的行为,修改缓冲区的大小,设置套接字选项等。该函数的参数众多,理解每个参数的作用对于正确使用该函数非常重要...

    Nginx高性能Web服务器详解.pdf

    在服务器优化部分,本书会探讨如何调整Nginx的性能参数,如worker_processes、keepalive_timeout等,以适应不同场景的需求。同时,还会介绍如何通过日志分析工具监控和调试Nginx,以便及时发现并解决性能瓶颈。 ...

    BGP路由协议详解

    **BGP路由协议详解** BGP(Border Gateway Protocol)是一种域间路由协议,主要用于在不同的自治系统(AS)之间交换路由信息。BGP的核心目的是确保网络中的数据包能够沿着无环路的最佳路径传输。它的最新版本是BGP4...

    Apache配置文件详解

    ### Apache配置文件详解 #### 一、概述 Apache配置文件是Apache Web服务器的核心组成部分,用于定义服务器的行为方式、性能参数及安全策略等。通过合理的配置,可以极大地提高Apache的性能和安全性,使其能够更好...

    Apache 的 httpd.conf 详解

    ### Apache的httpd.conf配置详解 #### 一、概述 `httpd.conf` 是Apache Web服务器的核心配置文件,它控制着服务器的行为与功能。通过合理地配置这些参数,可以极大地提高服务器的安全性、性能和可扩展性。下面将对...

Global site tag (gtag.js) - Google Analytics