01、目录
02、引言
两个进程之间如果要通信,很显然必须要建立一个连接,通过它来相互传输数据。在网络通信过程中,主机与主机之前一般情况下是通过通过TCP协议进行连接的,既然是连接,那么就会有连接时间的长短,长时间的连接称之为长连接,短时间的连接称之为短连接,在长连接的过程中,由于是长时间连接,所以对于服务器来说,需要去判断连接进来的客户端是不是还在连接的过程中,这里就涉及到心跳的问题。就像人的心跳一样,每跳动一次,就发出一个消息,看看能不能得到回应,如果能得到回应,说明客户端还在连接的过程中,如果得不到回应,在一定的心跳次数下依然得不到回应,就判断长连接断开了。
关于TCP/IP协议,如不清楚请看我上篇文章:https://blog.csdn.net/m0_43458204/article/details/107424287
上面的介绍,完全是字面意思,下面我们通过图文来一起详细了解下长连接、短连接、心跳机制。
声明:本文不涉及Code,至于代码,如果有时间我会去Linux系统那边写好之后写后续,如果是为了深入理解三者,请继续,如是为了Code,这里就先不浪费各位宝贵时间。
03、网络通讯——长连接
3.1 网络通讯——长连接<介绍>
长连接意味着进行一次数据传输后,不关闭连接,长期保持连通状态。如果两个应用程序之间有新的数据需要传输,则直接复用这个连接,无需再建立一个新的连接,如下图:
长连接关键字:一次连接,多次数据交互,实现连接复用!
3.2 网络通讯——长连接<优缺点>
3.2.1 优点(Advantage)
-
连接少:长连接的存在减少了网络通讯时建立连接和关闭连接时的开销,因为每次的连接断开都要进行三次握手、四次挥手操作,其中花费的时间却不是固定的,比如:
同城的机器之间的大概是0-5ms级别的延时,影响还不大
如果是北京和上海两地机房,走专线一来一回大概需要30ms,如果使用长连接,这个优化还是十分可观的。 -
方便实现push数据:数据交互-推模式实现的前提是网络长连接,有了长连接,连接两端很方便的互相push数据,来进行交互。
3.2.2 缺点(Defect)
- 需要花费额外的精力来保持这个连接一直是可用的,因为网络抖动、服务器故障等都会导致这个连接不可用,甚至是由于防火墙的原因。所以,一般我们会通过下面这几种方式来做“保活”工作,确保连接在被使用的时候是可用状态:
1):利用 TCP 自身的保活(Keepalive)机制来实现,保活机制会定时发送探测报文来识别对方是否可达。一般的默认定时间隔是 2 小时,你可以根据自己的需要在操作系统层面去调整这个间隔,不管是 Linux 还是 Windows 系统。
2):上层应用主动的定时发送一个小数据包作为“心跳”,探测是否能成功送达到另外一端。 保活功能大多数情况下用于服务端探测客户端的场景,一旦识别客户端不可达,则断开连接,缓解服务端压力。(即心跳机制)
3.3 网络通讯——长连接<生命周期>
正常情况下一直存在。正常情况下,一条TCP长连接建立后,只要双方不提出关闭请求并且不出现异常情况,这条连接是一直存在的.操作系统不会自动去关闭它,甚至经过物理网络拓扑的改变之后仍然可以使用。所以一条连接保持几天、几个月、几年或者更长时间都有可能,只要不出现异常情况或由用户(应用层)主动关闭。客户端和服务端可一直使用该连接进行数据通信。
3.4 网络通讯——长连接<应用场景>
应用场景总体来说,满足1、高频 2、服务器主动推送 3、有状态
具体如下:
- 数据库的连接就是采用TCP长连接.
- RPC,远程服务调用,在服务器,一个服务进程频繁调用另一个服务进程,可使用长连接,减少连接花费的时间。
实例:大型、成熟的股票软件
成熟股票软件的服务端,为了支撑更多的用户以及做高可用,必然部署了多台。但是这个业务场景,用户无法容忍由于多个服务端之间数据同步的误差导致他在客户端看到的价格刷新产生“回退”现象。所以,只能尽量保持一直连接在同一台服务器上,才能避免这个情况。这种场景被称之为“有状态”,也可以理解为是“串行”的,因为多次请求的前后需要保持“连续性”。
04、网络通讯——短连接
4.1 网络通讯——短连接<介绍>
短连接意味着每一次的数据传输都需要建立一个新的连接,用完再马上关闭它。下次再用的时候重新建立一个新的连接,如此反复,如下图:
短连接关键字:多次连接、间断通讯!
4.2 网络通讯——短连接<优缺点>
4.2.1 优点(Advantage)
- 由于每次使用的连接都是新建的,所以基本上只要能够建立连接,数据就大概率能送达到对方。并且哪怕这次传输出现异常也不用担心影响后续新的数据传输,因为届时又是一个新的连接。
4.2.2 缺点(Defect)
-
缺点是每个连接都需要经过三次握手和四次握手的过程,耗时大大增加。
-
短连接还有一个致命的缺点:socket 包含通信协议、目标地址、状态等。实际当你在基于 socket 进行开发的时候,这些包含的具体资源主要就是这 5 个:源 IP、源端口、目的 IP、目的端口、协议,有个专业的叫法称之为“五元组”。在一台计算机上只要这五元组的值不重复,那么连接就可以被建立。然而一台计算机最多只能开启 65535 个端口,如果现在两个进程之间需要通信,作为服务端的 IP 和端口必然是固定的,因此单个客户端理论上最多只能与服务端同时建立 65535 个 socket 连接。如果除去操作系统和其它进程所占用的端口,实际还会更少。所以,一旦使用不当,在很短的时间内建立了大量连接,端口很容易被占用完。这不但会导致自身无法正常工作,还会影响到同一台计算机上的其它进程。
在项目中大多数情况使用的是短连接的方式,因为这对我们编程来说可以少考虑很多问题,潜在的这些缺点可能是你没有遇到或者意识到而已。存在必有其价值,
4.3 网络通讯——短连接<生命周期>
想必对比长连接大家都知道了,短连接的生命周期就是连接上到连接关闭这段期间。
4.4 网络通讯——短连接<应用场景>
应用场景总体来说满足:1、低频 2、无状态
短连接适用于诸如阅读类软件的场景中,
例如,很多时候用户点开一篇文章后需要花一些时间进行阅读,这个时间有长有短,并且直到用户下一次操作之前都没有数据传输发生。这个场景中包含了运用短连接的两个主要因素:低频、无状态。
例如:网站响应请求,这也是属于短连接,有了事件(event)我就响应,没有我就不做事。可能有很多人在这里想说,网页响应不是HTTP协议和HTTPS协议嘛,这里说的是TCP/IP啊。
解释一下:不管是HTTP/HTTPS,还是TCP/IP,他们都是基于IP。只是通过特殊的封装而已。
- 因为低频,所以更能容忍建立连接和关闭连接的开销。
- 用户的下一次点击往往跳转到了其它文章,并且新打开的与当前文章并不需要具有“连续性”,所以这种场景我们称之为“无状态”的。另外,理论上同一时刻打开几篇文章也不会存在什么不妥。
05、心跳机制(重点)
心跳这个名字比较形象,就像人体心跳一样,是用来检测一个系统是否存活或者网络链路是否通畅的一种方式,其一般做法是定时向被检测系统发送心跳包,被检测系统收到心跳包进行回复,收到回复说明对方存活。
在上面长连接中有提到过心跳机制,没错,正是长连接的缺点,必须利用心跳机制。我之所以不和长连接一起说,就是因为,我觉得分开说更能体现他的重要程度。
5.1 心跳机制在长连接的“保活流程”
TCP协议实现中,是有保活机制的,也就是TCP的KeepAlive机制(此机制并不是TCP协议规范中的内容,由操作系统去实现),KeepAlive机制开启后,在一定时间内(一般时间为7200s,参数tcp_keepalive_time)在链路上没有数据传送的情况下,TCP层将发送相应的KeepAlive探针以确定连接可用性,探测失败后重试10(参数tcp_keepalive_probes)次,每次间隔时间75s(参数tcp_keepalive_intvl),所有探测失败后,才认为当前连接已经不可用。这些参数是机器级别,可以调整。
5.2 出于对时间的考虑“心跳机制”
按照TCP的KeepAlive机制,默认的参数,显然不能满足要求。那是不是调小点就可以了呢?
调整参数,当然是有用的,但是首先参数的机器级别的,调整起来不太方便,更换机器还得记得调整参数,对系统的使用方来说,未免增加了维护成本,而且很可能忘记;其次由于KeepAlive的保活机制只在链路空闲的情况下才会起到作用,假如此时有数据发送,且物理链路已经不通,操作系统这边的链路状态还是ESTABLISHED,这时会发生什么?自然会走TCP重传机制,要知道默认的TCP超时重传,指数退避算法也是一个相当长的过程。因此,一个可靠的系统,长连接的保活肯定是要依赖应用层的心跳来保证的。
这里应用层的心跳举个例子,比如客户端每隔3s通过长连接通道发送一个心跳请求到服务端,连续失败5次就断开连接。这样算下来最长15s就能发现连接已经不可用,一旦连接不可用,可以重连,也可以做其他的failover处理,比如请求其他服务器。
应用层心跳还有个好处,比如某台服务器因为某些原因导致负载超高,CPU飙高,或者线程池打满等等,无法响应任何业务请求,如果使用TCP自身的机制无法发现任何问题,然而对客户端而言,这时的最好选择就是断连后重新连接其他服务器,而不是一直认为当前服务器是可用状态,向当前服务器发送一些必然会失败的请求。
5.3 心跳机制设计误区
5.3.1 无心跳
通常情况下,我们均是使用无心跳,不考虑重连的情况。
无心跳的设计,也是很常见的,为了省事,长连接断开,TCP传输层有通知,应用程序只要处理这种通知,一旦发现连接异常,就重连。但是此类通知可能来的特别晚,比如在机器奔溃,应用程序异常退出,链路不通等情况下。
5.3.2 有心跳
心跳的实现分为心跳的发送和心跳的检测,心跳由谁来发都可以,也可以双方都发送,但是检测心跳,必须由发起连接的这端进行,才安全。因为只有发起连接的一端检测心跳,知道链路有问题,这时才会去断开连接,进行重连,或者重连到另一台服务器。
例如,client去连接server,client定时发送心跳到server,server检测心跳,发现一段时间client没有传心跳过来,认为与client的链路已经出了问题或者client自身就已经出了问题。粗看上去貌似没什么问题,但是如果只是client与当前这个server之间的链路出了问题,作为一个高可用的系统,是不是应该还有另一个server作为备选,问题出在短时间内client根本不知道自己和第一个server出了问题,所以也不会主动去连接第二个server。
5.3.3 第三方心跳
还有一类心跳,使用第三方保活,也就是除了客户端和服务端之外,还有另一台机器,定时发送心跳去探测服务端的存活。这类探活方法使用在检测系统的存活与否的问题上是没有问题的,但是这类设计是无法用来检测客户端和服务端之间链路的好坏。
5.4 心跳机制优化
对于这种每隔n秒就发送一个包,即使,我们考虑最理想的情况,发送空包来用作心跳监测,也是有多余时间消耗的,这个时候就想到能不能优化一下。答案肯定是有的。
既然你是为了监测连接是否ok,那么,在你们通讯的时候,你们通讯的内容也就可以算作心跳包,这个时候我们就不发送多余的心跳监测包,待到通讯空闲时,心跳包再按流程监测,发送即可。
这样做的虽然优化不是很大,但是当积累起来,还是比较好的。
关于心跳机制就介绍到这里。
06、附录与总结
- 附录
下面列举此文中引用、借鉴的文章如下:
https://www.jianshu.com/p/c6af08f853d0
https://cloud.tencent.com/developer/article/1470024
- 总结
下面做下补充:
- 长连接适用于:两个进程之间需要高频通信并且具备服务端主动推送或者有状态(需串行)两者之一的场景,否则并不是必选项。
- 补充一句,如果在做了高可用的分布式系统场景中运用长连接会更麻烦一些。因为高可用必然包含自动故障转移、故障隔离等机制。这恰恰导致了一旦发生故障,客户端需要及时发现哪些连接已处于不可用状态,并进行相应的重连,包括重新做负载均衡等工作。
- 短连接适用于:两个进程之间通信频率较低,或者属于无状态(可并行)的场景,否则并不是必选项。
其它情况就根据所需的侧重点来,比如侧重性能就长连接,侧重编码的便捷性就选择短连接。
版权声明:转载请注明出处,谢谢!