`
san_yun
  • 浏览: 2655345 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

再谈KeepAlive

    博客分类:
  • TCP
 
阅读更多

为什么要有KeepAlive?

在谈KeepAlive之前,我们先来了解下简单TCP知识(知识很简单,高手直接忽略)。首先要明确的是在TCP层是没有“请求”一说的,经常听到在TCP层发送一个请求,这种说法是错误的。TCP是一种通信的方式,“请求”一词是事务上的概念,HTTP协议是一种事务协议,如果说发送一个HTTP请求,这种说法就没有问题。也经常听到面试官反馈有些面试运维的同学,基本的TCP三次握手的概念不清楚, 面试官问TCP是如何建立链接,面试者上来就说,假如我是客户端我发送一个请求给服务端,服务端发送一个请求给我。。。这种一听就知道对TCP基本概念不清楚。下面是我通过wireshark抓取的一个TCP建立握手的过程。(命令行基本上用TCPdump,后面我们还会用这张图说明问题):

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

tcp_syn_synack_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
TCP
KEEPIDLE: 覆盖 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_session

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

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

 519 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
 520                 
 521         if (ls[i].keepidle) { 
 522             if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
 523                            (const void *) &ls[i].keepidle, sizeof(int))
 524                 == -1)
 525             {
 526                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
 527                               "setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
 528                               ls[i].keepidle, &ls[i].addr_text);
 529             }
 530         }

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

so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]
on表示开启
off表示关闭
有些系统提供跟精确的控制,比如linux:
    keepidle表示等待时间,keepintvl表示探测报的发送间隔,keepcnt表示探测报文发送的次数。

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

参考资料

《TCP/IP协议详解VOL1》--强烈建议对于网络基本知识不清楚同学有空去看下。

http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#overview

http://nginx.org/en/docs/http/ngx_http_core_module.html

Nginx Source code: https://github.com/alibaba/tengine

(文章转自我的blog, 欢迎大家访问http://blog.sunburst-tech.net/,墙外需科学上网,你懂的。)

http://coolshell.cn/articles/11564.html

分享到:
评论

相关推荐

    GRE隧道keepalive的说明

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

    W5500 Keepalive 应用笔记

    "W5500 Keepalive 应用笔记"是一个针对W5500网络接口芯片的专题,旨在探讨如何在TCP连接中有效地使用Keepalive机制。W5500是一款集成的以太网控制器,广泛应用于嵌入式系统,如物联网设备和工业自动化。 TCP ...

    socket的keepalive介绍

    Socket的Keepalive机制是TCP/IP通信中用于保持连接活跃性的一种技术。它的主要目标是确保在TCP连接上,即使在长时间无数据交换的情况下,也能检测到连接是否仍然有效。这在服务器与客户端通信中尤其重要,因为如果...

    springboot-keepalive设置测试

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

    linux tcp keepalive存活代码设置

    如果在keepalive_time时间内双方没有任何的数据包传输,则开启keepalive功能的一端将发送 eepalive数据包,若没有收到应答,则每隔keepalive_intvl时间再发送该数据包,发送keepalive_probes次。一直没有 收到应答,...

    keepalive--aarch64.rar

    标题中的"keepalive--aarch64.rar"表明这是一个针对aarch64架构的软件或程序,使用了“keepalive”技术,并且被压缩在RAR文件格式中。RAR是一种流行的压缩格式,通常用于存储和传输大量数据,因为它可以提供较高的...

    keepalive1.1.17.zip

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

    Keepalive+mysql主主同步.pdf

    "Keepalive+mysql主主同步" Keepalive+mysql主主同步是指在高可用性环境中,使用Keepalive和MySQL主主同步技术来实现数据库的高可用性和负载均衡。下面是相关的知识点: 一、Keepalive简介 Keepalive是一个高可用...

    nginx1.9.7+keepalive1.3.2

    标题 "nginx1.9.7+keepalive1.3.2" 暗示我们要讨论的是一个特定版本的 Nginx 服务器软件,与 Keepalive 模块的结合使用。Nginx 是一款广泛使用的高性能 web 服务器和反向代理服务器,而 Keepalive 模块则是增强其...

    判定断开前的KeepAlive探测次数

    在IT网络管理与系统运维领域,理解“判定断开前的KeepAlive探测次数”这一概念至关重要,尤其是在处理网络连接状态及优化系统性能方面。本文将深入解析这一知识点,结合给出的描述与部分代码示例,旨在提供一个全面...

    nginx+keepalive主从 双机热备

    nginx+keepalive 主从双机热备解决方案 nginx 是一种流行的开源 Web 服务器软件,keepalive 是一种心跳检测机制,用于检测服务器的健康状态。nginx+keepalive 主从双机热备解决方案是指使用 nginx 和 keepalive ...

    Mysql keepalive-1.4.5.tar.gz

    MySQL Keepalive是一款用于保持MySQL连接活性的工具,它在数据库管理中扮演着重要角色,尤其在高并发、长时间无操作的场景下。标题中的“Mysql keepalive-1.4.5.tar.gz”指的是该软件的1.4.5版本的压缩包文件,通常...

    keepalive--aarch64

    keepalive--aarch64

    KEEPALIVE安装配置手册

    KEEPALIVE安装配置手册 REDIS集群配置 各种算法分析

    KeepAlive.zip

    标题为"KeepAlive.zip"的压缩包文件中可能包含源代码、资源文件等,用于构建这样一个实用的小程序。我们将主要关注以下几个关键知识点: 1. **Qt框架**:Qt是一个跨平台的应用程序开发框架,用C++编写,广泛用于...

    keepalive中文文档

    标题"keepalive中文文档"指出,我们关注的是与"keepalive"相关的技术内容,而这份资源是用中文编写的,适用于学习和开发用途。描述中的"pdf格式的保证好用"表明这是一个PDF文件,通常包含详细的教程或指南,适合读者...

    nginx+keepalive

    在构建高可用性网络服务时,`nginx+keepalive` 的组合是一个常用方案。Nginx 是一款高性能的 HTTP 和反向代理服务器,而 Keepalive 则是用于实现虚拟 IP (VIP) 高可用和负载均衡的工具。下面将详细介绍这两个组件...

    Nginx和Keepalive

    【Nginx与Keepalive整合实现高可用负载均衡】 Nginx是一款高性能的HTTP和反向代理服务器,常用于构建高可用的Web服务系统。在本文中,我们将深入探讨如何结合Keepalive工具来实现Nginx的高可用负载均衡。 **一、...

    keepalive应用脚本

    "keepalive应用脚本"是一个专门设计来确保MySQL主从复制环境持续运行的工具。它包含两个主要部分:主库监控和从库监控,以及主从切换的shell脚本。 **Keepalive机制** "Keepalive"通常指的是在网络连接中保持活动...

    Niginx操作配置+KeepAlive负载均衡

    关闭时,会等待一定量的数据再发送,减少网络交互次数。 3. **Nginx负载均衡**: - **upstream模块**:Nginx使用upstream模块进行反向代理和负载均衡,定义一组后端服务器,并通过不同的负载均衡策略将请求分发到...

Global site tag (gtag.js) - Google Analytics