Home Tags Posts tagged with "长连接"

长连接

0 67

上篇博文讲解了有关长连接的概念

接下来该讲解心跳了

为什么会出现心跳?

因为长连接自带的保活机制不太完善,虽然可以通过调参的方式来提升性能,但还是不够用,因此我们引入心跳机制

介绍

  • 长连接
    首先这里所说的连接是指网络传输层的使用TCP协议经过三次握手建立的连接;长连接是指建立的连接长期保持,不管此时有无数据包的发送;有长连接自然也有短连接,短连接是指双方有数据发送时,就建立连接,发送几次请求后,就主动或者被动断开连接。
  • 心跳
    心跳这个名字比较形象,就像人体心跳一样,是用来检测一个系统是否存活或者网络链路是否通畅的一种方式,其一般做法是定时向被检测系统发送心跳包,被检测系统收到心跳包进行回复,收到回复说明对方存活。

心跳和长连接在一起介绍的原因是,心跳能够给长连接提供保活功能,能够检测长连接是否正常(这里所说的保活不能简单的理解为保证活着,具体来说应该是一旦链路死了,不可用了,能够尽快知道,然后做些其他的高可用措施,来保证系统的正常运行)。

优势

长连接的优势

  • 减少连接建立过程的耗时
    大家都知道TCP连接建立需要三次握手,三次握手也就说需要三次交互才能建立一个连接通道,同城的机器之间的大概是ms级别的延时,影响还不大,如果是北京和上海两地机房,走专线一来一回大概需要30ms,如果使用长连接,这个优化还是十分可观的。
  • 方便实现push数据
    数据交互-推模式实现的前提是网络长连接,有了长连接,连接两端很方便的互相push数据,来进行交互。

疑问

  • TCP连接到底是什么?
    所谓的TCP连接不是物理的连接,是为了实现数据的可靠传输由通信双方进行三次握手交互而建立的逻辑上的连接,通信双方都需要维护这样的连接状态信息。比如netstat经常看到连接的状态为ESTABLISHED,表示当前处于连接状态。(这里需要注意的是这个ESTABLISHED的连接状态只是操作系统认为当前还处在连接状态
  • 是不是建立了长连接,就可以高枕无忧了呢?
    建立好长连接,两端的操作系统都维护了连接已经建立的状态,是不是这时向对端发送数据一定能到达呢?
    答案是否定的。
    可能此时链路已经不通,只是TCP层还没有感知到这一信息,操作系统层面显示的状态依然是连接状态而且因为TCP层还认为连接是ESTABLISHED,所以作为应用层自然也就无法感知当前的链路不通。
    这种情况会导致什么问题?
    如果此时有数据想要传输,显然,数据是无法传送到对端,但是TCP协议为了保证可靠性,会重传请求,如果问题只是网线接头松了,导致网络不通,此时如果及时将网线接头接好,数据还是能正常到达对端,且TCP的连接依然是ESTABLISHED,不会有任何变化。但不是任何时候都这么巧,有时就是某段链路瘫痪了,或者主机挂了,系统异常关闭了等。这时候如果应用系统不能感知到,是件很危险的事情。

    个人理解:

建立长连接之后并非高枕无忧

因为操作系统层面显示的状态还是连接状态,操作系统说,我认为连接还没断开

由于TCP是在操作系统之上的(层次来讲)

操作系统告诉TCP层说:我认为连接还没断开
TCP:哦,好的
于是TCP又告诉应用层:连接还没断开呢
应用层:哦,好的

也就是传达了错误信息,如果现在想要传输数据怎么办?
因为事实上已经连接不通了,但操作系统,TCP,应用层都认为还可以传输,那么他们就会进行传输
结果发现,诶,传不过去
这个时候TCP的重传特性出现了
TCP:传不过去,我重新再传呗,再来

那么,如果事实上出现的是网络接线松了,或者网线被拔掉了,此时接上,数据还能正常到达对端,
但是
如果很不巧,是传输中间的链路瘫痪了,或者对端的这个主机挂了,系统异常被入侵了等等
这个时候应用系统不能感知到,那就很可怕了
这个资源的浪费是巨大的

 

  • 长连接怎么保活?
    TCP协议实现中,是有保活机制的,也就是TCP的KeepAlive机制(此机制并不是TCP协议规范中的内容,由操作系统去实现),KeepAlive机制开启后,在一定时间内(一般时间为7200s,参数tcp_keepalive_time)在链路上没有数据传送的情况下,TCP层将发送相应的KeepAlive探针以确定连接可用性,探测失败后重试10(参数tcp_keepalive_probes)次,每次间隔时间75s(参数tcp_keepalive_intvl),所有探测失败后,才认为当前连接已经不可用。这些参数是机器级别,可以调整。
  • 应用层需要做点什么吗?(心跳)
    按照TCP的KeepAlive机制,默认的参数,显然不能满足要求。那是不是调小点就可以了呢?
    调整参数,当然是有用的,但是首先参数的机器级别的,调整起来不太方便,更换机器还得记得调整参数,对系统的使用方来说,未免增加了维护成本,而且很可能忘记;其次由于KeepAlive的保活机制只在链路空闲的情况下才会起到作用,假如此时有数据发送,且物理链路已经不通,操作系统这边的链路状态还是ESTABLISHED,这时会发生什么?自然会走TCP重传机制,要知道默认的TCP超时重传,指数退避算法也是一个相当长的过程。因此,一个可靠的系统,长连接的保活肯定是要依赖应用层的心跳来保证的。
    这里应用层的心跳举个例子,比如客户端每隔3s通过长连接通道发送一个心跳请求到服务端,连续失败5次就断开连接。这样算下来最长15s就能发现连接已经不可用,一旦连接不可用,可以重连,也可以做其他的failover处理,比如请求其他服务器。
    应用层心跳还有个好处,比如某台服务器因为某些原因导致负载超高,CPU飙高,或者线程池打满等等,无法响应任何业务请求,如果使用TCP自身的机制无法发现任何问题,然而对客户端而言,这时的最好选择就是断连后重新连接其他服务器,而不是一直认为当前服务器是可用状态,向当前服务器发送一些必然会失败的请求。

    设计误区

    • 无心跳
      无心跳的设计,也是很常见的,为了省事,长连接断开,TCP传输层有通知,应用程序只要处理这种通知,一旦发现连接异常,就重连。但是此类通知可能来的特别晚,比如在机器奔溃,应用程序异常退出,链路不通等情况下。
    • 被连接方检测心跳
      心跳的实现分为心跳的发送和心跳的检测,心跳由谁来发都可以,也可以双方都发送,但是检测心跳,必须由发起连接的这端进行,才安全。因为只有发起连接的一端检测心跳,知道链路有问题,这时才会去断开连接,进行重连,或者重连到另一台服务器。
      例如,client去连接server,client定时发送心跳到server,server检测心跳,发现一段时间client没有传心跳过来,认为与client的链路已经出了问题或者client自身就已经出了问题。粗看上去貌似没什么问题,但是如果只是client与当前这个server之间的链路出了问题,作为一个高可用的系统,是不是应该还有另一个server作为备选,问题出在短时间内client根本不知道自己和第一个server出了问题,所以也不会主动去连接第二个server。
    • 第三方心跳
      还有一类心跳,使用第三方保活,也就是除了客户端和服务端之外,还有另一台机器,定时发送心跳去探测服务端的存活。这类探活方法使用在检测系统的存活与否的问题上是没有问题的,但是这类设计是无法用来检测客户端和服务端之间链路的好坏。

    参考方案

    • 方案一
      最简单的策略当然是客户端定时n秒发送心跳包,服务端收到心跳包后,回复客户端的心跳,如果客户端连续m秒没有收到心跳包,则主动断开连接,然后重连,将正常的业务请求暂时不发送的该台服务器上。
    • 方案二
      可能有人觉得,这样是不是传送一些无效的数据包有点多,是不是可以优化下,说实话,个人认为其实一点也不多。当然是可以做些优化的,因为心跳就是一种探测请求,业务上的正常请求除了做业务处理外,还可以用作探测的功能,比如此时有请求需要发送到服务端,这个请求就可以当作是一次心跳,服务端收到请求,处理后回复,只要服务端有回复,就表明链路还是通的,如果客户端请求比较空闲的时候,服务端一直没有数据回复,就使用心跳进行探测,这样就有效利用了正常的请求来作为心跳的功能,减少无效的数据传输。

0 68

最近开始学习netty,作为一个大三学生,却刚刚开始接触网络编程实在惭愧,路上遇到许多的新知书点,特此记录(个人理解+转载:https://zhuanlan.zhihu.com/p/224595048

 

补充:

长连接与短连接

TCP 本身并没有长短连接的区别,长短与否,完全取决于我们怎么用它。

  • 短连接:每次通信时,创建 Socket;一次通信结束,调用 socket.close()。这就是一般意义上的短连接,短连接的好处是管理起来比较简单,存在的连接都是可用的连接,不需要额外的控制手段。
  • 长连接:每次通信完毕后,不会关闭连接,这样就可以做到连接的复用。长连接的好处便是省去了创建连接的耗时。

短连接和长连接的优势,分别是对方的劣势。想要图简单,不追求高性能,使用短连接合适,这样我们就不需要操心连接状态的管理;想要追求性能,使用长连接,我们就需要担心各种问题:比如端对端连接的维护,连接的保活。

长连接还常常被用来做数据的推送,我们大多数时候对通信的认知还是 request/response 模型,但 TCP 双工通信的性质决定了它还可以被用来做双向通信。在长连接之下,可以很方便的实现 push 模型。

 

文章目录
一、简介
  1.1、TCP协议简介
  1.2、HTTP协议简介
二、TCP keepalive
  2.1、简介
  2.2、实验
  2.3、扩展
三、HTTP keep-alive
  3.1、简介
  3.2、实验
    3.2.1、实验一:禁用keep-alive的http请求
    3.2.2、实验二:启用keep-alive的http请求
  3.3、扩展
四、总结
五、彩蛋

1、从文中找出我的IP
2、http请求中是客服端还是服务端主动关闭的tcp连接?
请阅读到最后的彩蛋部分

HTTP和TCP都是老生常谈的知识点,本文不进行铺开赘述。我们可能在HTTP和TCP中都听说“长连接”的说法,也听过HTTP中有keep-alive,TCP中有keepalive。那么,HTTP和TCP的长连接有何区别?HTTP中的keep-alive和TCP中keepalive又有什么区别?

Tips:HTTP中是keep-alive,TCP中是keepalive,HTTP中是带中划线的。大小写无所谓。

一、简介

上面是我先前做TCP协议分享时整理的一张表格,从上面可以看出:不管是在OSI七层网络模型还是在TCP/IP五层网络模型中,TCP是传输层的一种协议,而HTTP是应用层的一种协议

HTTP和TCP的理论和实现还是相当复杂的,下面只简单介绍和本文主题相关的知识点。

 

1.1、TCP协议简介

TCP协议也叫传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。使用TCP的两个程序(客户端和服务端)在交换数据前,通过三次握手来建立TCP连接,建立连接后就可以进行基于字节流的双工通讯,由TCP内部实现保证通讯的可靠性,完全通讯完成后,通过四次挥手断开连接。

在客户端和服务端间的网络一切正常、且双方都没主动发起关闭连接的请求时,此TCP连接理论上可以永久保持。但是,网络情况是及其复杂的,在双方长时间未通讯时,如何得知对方还活着?如何得知这个TCP连接是健康且具有通讯能力的?

 

1.2、HTTP协议简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写。HTTP是万维网的数据通信的基础。HTTP是一个应用层协议,通常运行在TCP协议之上。它由请求和响应构成,是一个标准的客户端服务器模型(C/S模型)。HTTP是一个无状态的协议。

无状态怎么解释?HTTP协议永远都是客户端发起请求服务器回送响应。每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求客户端再重新建立连接。也就无法实现在客户端没有发起请求的时候,服务器主动将消息推送给客户端

HTTP无状态导致每次请求都需要重新建立TCP连接,接收到服务器相应后再断开TCP连接

HTTP协议运行在TCP协议之上,它无状态会导致客户端的每次请求都需要重新建立TCP连接,接受到服务端响应后,断开TCP连接。对于每次建立、断开TCP连接,还是有相当的性能损耗的。那么,如何才能尽可能的减少性能损耗呢?(建立长连接,HTTP1.1引入,可是建立了长连接,长连接并不是时时刻刻都在进行数据传输,怎么判断对方还活着呢?或者什么时候断开长连接呢?)

二、TCP keepalive

2.1、简介

正如上面提出的问题:在双方长时间未通讯时,如何得知对方还活着?如何得知这个TCP连接是健康且具有通讯能力的?

TCP的保活机制就是用来解决此类问题,这个机制我们也可以称作:keepalive。保活机制默认是关闭的,TCP连接的任何一方都可打开此功能。有三个主要配置参数用来控制保活功能。

如果在一段时间(保活时间:tcp_keepalive_time)内此连接都不活跃,开启保活功能的一端会向对端发送一个保活探测报文。

  • 若对端正常存活,且连接有效,对端必然能收到探测报文并进行响应。此时,发送端收到响应报文则证明TCP连接正常,重置保活时间计数器即可。
  • 若由于网络原因或其他原因导致,发送端无法正常收到保活探测报文的响应。那么在一定探测时间间隔(tcp_keepalive_intvl)后,将继续发送保活探测报文。直到收到对端的响应,或者达到配置的探测循环次数上限(tcp_keepalive_probes)都没有收到对端响应,这时对端会被认为不可达,TCP连接虽存在但已失效,需要将连接做中断处理。

在探测过程中,对端主机会处于以下四种状态之一:

2.2、实验

这里,强烈推荐《TCP/IP详解 卷1:协议》的第二版(这里一定是第二版), 第17章:TCP保活机制。这里建议17章都看,17.1和17.2小节就涵盖了我上面介绍的内容。

17.2.1 小节中还通过实验的方式详细验证了“对端主机会处于以下四种状态”以及对于这四种状态TCP都是如何去处理。

这本书中的实验已经比较通俗易懂了,我暂且没有亲自动手去模拟实践,后续时间充足,会亲自动手进行实验。

2.3、扩展

上面提到了三个参数保活时间:tcp_keepalive_time、探测时间间隔:tcp_keepalive_intvl、探测循环次数:tcp_keepalive_probes

这三个参数,在linux上可以在/proc/sys/net/ipv4/路径下找到,或者通过sysctl -a | grep keepalive命令查看当前内核运行参数。

[root@vm01 ~]# cd /proc/sys/net/ipv4
[root@vm01 ipv4]# pwd
/proc/sys/net/ipv4
[root@vm01 ipv4]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[root@vm01 ipv4]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
[root@vm01 ipv4]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
[root@vm01 ipv4]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
  • 保活时间(tcp_keepalive_time)默认:7200秒
  • 保活时间间隔(tcp_keepalive_intvl)默认:75秒
  • 探测循环次数(tcp_keepalive_probes)默认:9次

也就是默认情况下一条TCP连接在2小时(7200秒)都没有报文交换后,会开始进行保活探测,若再经过9*75秒=11分钟15秒的循环探测都未收到探测响应,即共计:2小时11分钟15秒后会自动断开TCP连接。

别走开,还有一个骚操作

Linux平台下我们还可以借助man命令查看TCP协议的一些描述和参数定义。下面两个命令的效果相同:

  • 命令一:man tcp
  • 命令二:man 7 tcp

数字7的含义是:man命令使用手册共9章,TCP的帮助手册位于第7章。不知道在第几章也无所谓,使用man tcp也可,弹出的手册左上角也有写第几章。(man ls等同于man 1 lsman ip等同于man 8 ip,可以自己尝试使用 )。

下面我们看下man tcp下的和我们本文有关的几个点:

上面介绍的三个参数tcp_keepalive_time、tcp_keepalive_intvl、tcp_keepalive_probes都是系统级别的,针对整个系统生效。下面介绍针对单条Socket连接细粒度设置的三个选项参数:保活时间:TCP_KEEPIDLE、保活探测时间间隔:TCP_KEEPINTVL、探测循环次数:TCP_KEEPCNT

在我们的Netty的框架中可以看到针对Socket选项的配置,如使用epoll的IO模型中EpollSocketChannelConfig类中的配置:

更多细节,等你挖掘。

三、HTTP keep-alive(又叫持久连接 HTTP/1.1)

3.1、简介

HTTP协议简介中提到http协议是一个运行在TCP协议之上的无状态的应用层协议。它的特点是:客户端的每一次请求都要和服务端创建TCP连接,服务器响应后,断开TCP连接。下次客户端再有请求,则重新建立连接。

在早期的http1.0中,默认就是上述介绍的这种“请求-应答”模式。这种方式频繁的创建连接和销毁连接无疑是有一定性能损耗的。

所以引入了keep-alive机制。http1.0默认是关闭的,通过http请求头设置“connection: keep-alive”进行开启;http1.1中默认开启,通过http请求头设置“connection: close”关闭。

keep-alive机制:若开启后,在一次http请求中,服务器进行响应后,不再直接断开TCP连接,而是将TCP连接维持一段时间。在这段时间内,如果同一客户端再次向服务端发起http请求,便可以复用此TCP连接,向服务端发起请求,并重置timeout时间计数器,在接下来一段时间内还可以继续复用。这样无疑省略了反复创建和销毁TCP连接的损耗。

3.2、实验

下面用两组实验证明HTTP keep-alive的存在。

实验工具:Wireshark

客户端IP:*.*.3.52

服务端IP:*.*.17.254

3.2.1、实验一:禁用keep-alive的http请求

从上图请求列表区中,我们可以发现:

  • 106、107、108三个请求是TCP建立连接三次握手的请求
  • 109、110两个请求分别是:http的请求报文和http的响应报文
  • 111、112、120、121这四个请求是TCP断开连接四次挥手的请求

(由于一台机器上网络请求较多,我加了筛选条件,仅显示客户端和服务端通信的网络请求,所以请求的序号是不连续的)

从上图中间的请求数据解析区,可以确定:此次http请求的请求头中有“Connection: close”,即keep-alive是关闭的。

结论:禁用keep-alive的http请求时,会先建立TCP连接,然后发送报文、响应报文、最后断开TCP连接。

3.2.2、实验二:启用keep-alive的http请求

这次实验请求较多,一张图放不下,两张图是连续的,图1的第二块绿色区域和图2的第一块绿色区域是重叠的(注意看第一列的No.编号)

先说下我的操作:

  1. 开启keep-alive前提下发起第一次http请求
  2. 7秒左右时,同样的机器同样的http请求,再重新调用一次

我们根据图中抓包,分析下网络请求:

  • 197、198、199请求:三次握手建立TCP建立连接
  • 200、203请求:http的请求报文和http的响应报文
  • 212请求:可以通过Protocol列看到它是一条TCP报文。我的理解是:在keep-alive这种机制下,客户端收到服务端响应报文后,需要告知服务端“已收到”。由于要复用TCP连接,所以会多一层保障机制,类似TCP的握手和挥手
  • 459-1965请求(图1中的第一块黑色区域中):6秒内(第二列代表Time),每隔1秒,发生一对TCP请求的来回,用来维护TCP连接的可用性。保证和等待该TCP连接被复用
  • 1743、1744、1745、1755请求:其中的1743和1745是我第二次发起http请求的请求报文和响应报文。1744请求是:客户端发起请求时,服务端先回复客户端“已收到,马上处理”。紧接着1745将结果响应给客户端。1755则是客户端收到响应后,回复服务端“已收到响应,多谢”。
  • 2028-3903请求:10秒内,每隔1秒,发生一对TCP请求的来回,用来维护TCP连接的可用性。保证和等待该TCP连接被复用
  • 4127-4131请求:10秒内我没再发起http请求,四次挥手断开TCP连接。长时间没被复用,也没必要一直维持下去,浪费资源,还可能造成网络拥堵。

注意:10秒无请求,TCP连接在断开,10秒也不是默认的,只是环境的配置。是Httpd守护进程,提供的keep-alive timeout时间设置参数。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。

3.3、扩展

其实对于HTTP keep-alive机制可以总结为上图所示。

启用HTTP keep-Alive的优缺点:

优点:keep-alive机制避免了频繁建立和销毁连接的开销。 同时,减少服务端TIME_WAIT状态的TCP连接的数量(因为由服务端进程主动关闭连接)

缺点:若keep-alive timeout设置的时间较长,长时间的TCP连接维持,会一定程度的浪费系统资源。

总体而言,HTTP keep-Alive的机制还是利大于弊的,只要合理使用、配置合理的timeout参数。

四、总结

回到文章开头提出的问题:HTTP和TCP的长连接有何区别?HTTP中的keep-alive和TCP中keepalive又有什么区别?

1、TCP连接往往就是我们广义理解上的长连接,因为它具备双端连续收发报文的能力;开启了keep-alive的HTTP连接,也是一种长连接,但是它由于协议本身的限制,服务端无法主动发起应用报文。

2、TCP中的keepalive是用来保鲜、保活的;HTTP中的keep-alive机制主要为了让支撑它的TCP连接活的的更久,所以通常又叫做:HTTP persistent connection(持久连接) 和 HTTP connection reuse(连接重用)。

五、彩蛋

彩蛋一

你能从文中找出我在HTTP keep-alive实验中客户端和服务端的完整IP吗?

如能找出,说明对网络协议的了解已如火纯青。

彩蛋二

在HTTP请求中,到底是「服务端」还是「客户端」主动关闭连接呢?

看到过很多文章,有人说服务端、有人说客户端、有人说分情况(keep-alive的开启与否)既可能是客户端也可能是服务端。你信谁?最后翻来覆去发现各个网站的各种文章基本类似,只有观点,没有论据。

HTTP keep-alive章节的实验结果:无论开启keep-alive与否,最终由服务端主动断开TCP连接。

但是我给出问题的答案是:通常由服务端主动关闭连接。没有写“肯定由服务端主动关闭连接”的原因是,我没遇到客户端主动关闭连接的场景,并不代表没有。网络和协议博大精深,等待我们继续去探索。

这个彩蛋的目的由两个:

1、告诉大家:网上的文章、他人的观点,还是要思辨的看待。

2、我确实想知道什么情况下,客户端主动关闭连接?欢迎大家私信讨论,一定要有真凭实据

彩蛋三

  • Wireshark是一款功能强大的网络封包分析可视化软件。《TCP/IP详解 卷1:协议》第二版相比第一版,书中的抓包工具也将tcpdump改为*Wireshark。*
  • 个人观点:《TCP/IP详解 卷1:协议》第一版和第二版结合起来看效果更好。第一版的TCP阻塞控制将的更通俗易懂,第二版的TCP保活机制讲的更清晰。