长短连接的区别这么答,让面试官眼前一亮!

553 阅读10分钟

大家好,我是春哥,一名拥有10多年Linux后端研发经验的BAT互联网老兵。

最近看到有掘友提到面试中被问到“长短连接的区别是什么?”,该如何做出有亮点的回答,今天就和大家深入的聊一聊,长连接和短连接的那些事儿,干货如下。

1.澄清概念

在回答这个问题之前,我们需要先澄清概念,才能更有效的回答问题,那么什么是长连接,什么是短连接呢?

  • 长连接:“长”的字面意思是维持时间长,「连接长期存在,也就是说程序可以复用这条连接,不用每次发起请求都重新建立连接」。这就好比你要过河,然后修建了一座桥,大家都可以使用这座桥,这座桥被大家复用了。

  • 短连接:“短”的字面意思是维持时间短,「连接在请求结束之后就被释放了,也就是说程序无法复用这条连接,每次发起请求都要建立新的连接」。这就好比红蓝两军在交战,红军在追击蓝军,蓝军过河时搭建了一座桥,通过之后立马把桥炸毁,红军要过河只能再重新建桥。

长短连接的优缺点如表1-1所示。

表1-1 长短连接优缺点

优点缺点
长连接连接复用,每次请求耗时更短,性能更佳维护成本大:需要对连接进行保活,并维护好连接池
短连接每次都建立新连接,实现简单,代码易于理解和维护请求耗时上涨,连接无法复用,容易把下游服务的连接打满

2.区别仅此而已?

如果你的回答仅仅只有上面的内容的话,「那么你无法从众多的候选人中脱颖而出,从而得到面试官的青睐」。下面从4个不同方面深入回答这个问题。

2.1 如何量化耗时上涨

使用长连接完成请求,请求耗时会上涨,「那么上涨多少毫秒,这个是由什么决定的?具体该如何量化呢?」别着急,让我们先来看看一个连接的建立和释放的过程。

连接建立

连接建立过程如图2-1所示。

图2-1 连接建立

  • 服务端执行被动打开操作,在某个IP地址和端口上监听TCP连接请求,服务端的TCP连接状态从CLOSED变为LISTEN。
  • 客户端执行主动打开操作,向服务端发送一个带有SYN标志位的TCP报文段,客户端的TCP连接状态从CLOSED变为SYN_SENT。
  • 第一次握手:服务端接收到带有SYN标志位的TCP报文段后,回复一个带有SYN和ACK标志位的TCP报文段给客户端,服务端的TCP连接状态从LISTEN变为SYN_RCVD。
  • 第二次握手:客户端接收到带有SYN和ACK标志位的TCP报文段后,向服务端回复一个带有ACK标志位的TCP报文段,客户端的TCP连接状态从SYN_SENT变为ESTABLISHED。
  • 第三次握手:服务端接收到带有ACK标志位的TCP报文段后,服务端的TCP连接状态从SYN_RCVD变为ESTABLISHED。

连接释放

连接释放过程如图2-2所示。

图2-2 连接释放

  • 客户端和服务端正常进行双向数据传输,客户端请求结束后,主动关闭连接。此时,客户端和服务端的TCP连接状态都为ESTABLISHED。
  • 第一次挥手:客户端主动调用close函数关闭连接,发送一个带FIN标志位的TCP报文段给服务端。客户端的TCP连接状态从ESTABLISHED进入FIN_WAIT_1。
  • 第二次挥手:服务端在接收到带FIN标志位的TCP报文段后,回复一个带ACK标志位的TCP报文段给客户端。服务端的TCP连接状态从ESTABLISHED进入CLOSE_WAIT,而客户端接收到带ACK标志位的TCP报文段后,TCP连接状态从FIN_WAIT_1进入FIN_WAIT_2。
  • 第三次挥手:服务端被动调用close函数关闭连接,向客户端发送一个带FIN标志位的TCP报文段。服务端的TCP连接状态从CLOSE_WAIT进入LAST_ACK。
  • 第四次挥手:客户端接收到带FIN标志位的TCP报文段后,TCP连接状态从FIN_WAIT_2进入TIME_WAIT,并向服务端回复一个带ACK标志位的TCP报文段。服务端接收到带ACK标志位的TCP报文段后,TCP连接状态从LAST_ACK进入CLOSED。
  • 客户端等待2MSL(Maximum Segment Lifetime,在网络中TCP报文段最大的生存时间)的时间后,TCP连接状态从TIME_WAIT进入CLOSED。

增涨的耗时分析

从上面连接建立和连接释放过程中我们可以发现,「使用短连接的请求需要额外付出连接建立和连接释放的成本」,我们再分别分析一下这两部分的耗时分别是多少。

  • 连接建立,需要三次握手,需要的时间成本至少为「1个RTT时间」。
  • 连接释放,需要四次挥手,需要的时间成本至少为「1个RTT时间,但是因为close调用默认是立即返回的,连接释放不会阻塞进程,所以这个成本可以忽略不计」。

综上所述,「使用短连接的请求需要多付出至少一个RTT的时间」。那什么是RTT时间,如何测量RTT时间呢?

RTT测量

这个RTT时间是计算机网络中两台计算机之间TCP报文的往返时间,「而这是由物理距离来决定的,距离越远,RTT时间越长,例如上海IDC和深圳IDC之间的RTT就有50ms」。

我们可以使用ping命令来测量两台计算机之间的RTT时间。例如,我在本地Linux主机上执行ping命令来测量本地主机到百度搜索服务器的RTT时间。


[root@VM-114-245-centos ~]# ping www.baidu.com

PING www.a.shifen.com (14.119.104.254) 56(84) bytes of data.

64 bytes from 14.119.104.254: icmp_seq=1 ttl=52 time=3.89 ms

64 bytes from 14.119.104.254: icmp_seq=2 ttl=52 time=3.79 ms

64 bytes from 14.119.104.254: icmp_seq=3 ttl=52 time=3.95 ms

64 bytes from 14.119.104.254: icmp_seq=4 ttl=52 time=3.88 ms

64 bytes from 14.119.104.254: icmp_seq=5 ttl=52 time=4.14 ms

64 bytes from 14.119.104.254: icmp_seq=6 ttl=52 time=3.83 ms

64 bytes from 14.119.104.254: icmp_seq=7 ttl=52 time=4.03 ms

64 bytes from 14.119.104.254: icmp_seq=8 ttl=52 time=3.84 ms

64 bytes from 14.119.104.254: icmp_seq=9 ttl=52 time=3.90 ms

64 bytes from 14.119.104.254: icmp_seq=10 ttl=52 time=4.04 ms

64 bytes from 14.119.104.254: icmp_seq=11 ttl=52 time=3.81 ms

^C

--- www.a.shifen.com ping statistics ---

11 packets transmitted, 11 received, 0% packet loss, time 10014ms

rtt min/avg/max/mdev = 3.799/3.922/4.143/0.131 ms

[root@VM-114-245-centos ~]

从上面的输出可以看到,我本地主机到百度搜索服务器的RTT时间为3ms左右。

我们可以更近一步的思考,「RTT的测量是如何实现的呢?

ICMP回显请求

ICMP(网际控制报文协议)是TCP/IP协议栈中介于IP层和运输层之间的协议。其中,ICMP有一种请求类型为回显请求,而RTT就是通过ICMP的回显请求来实现的。

在ping程序中,每次发送一个ICMP回显请求报文,「这个请求中携带发送时的本地机器时间戳」。目的主机在收到这个请求之后,会回复一个ICMP的回显应答报文。ping程序在接收到这个报文之后,取出之前写入的发送时间戳,就可以计算RTT时间了。

由于篇幅的原因,这里就不展示具体的实现程序了。春哥计划单独另起一篇文章专门和大家一起聊聊该如何自己实现ping程序,大家记得关注春哥,下期分享不迷路。

2.2 连接如何保活

我们知道网络中的连接本质上是虚拟的连接,网络中的设备会启启停停,甚至连接两端的机器都可能随时启停或者被拔网线,因此连接不是建立了就万事大吉,连接是需要保活的。目前主流有3种连接保活策略。

  • 第1种:在运输层开启tcp协议的keep alive特性。
  • 第2种:在应用层使用应用层协议,做定期的心跳请求做连接保活,原理和tcp的keep alive特性类似,但是应用层的心跳保活可以探测到对端服务服务过载的情况,也更可控,也更及时。
  • 第3种:空闲连接释放,当发现连接空闲时间超过一定阈值时,则释放连接。

通常来说,第2种和第3种策略应用的比较多。

2.3 如何设置连接池大小

通常来说,我们可以通过系统的日常负载来评估连接池的大小。举个例子,如果你的系统日常的负载峰值为2000qps,接口平均耗时为50ms,那么连接池的大小就可以通过以下公式计算得出:2000 / (1000 / 50) = 100。这个公式的意思是,「单个连接一秒可以处理20(1000ms / 50ms)个请求,因此只需要100个连接就可以在1秒内处理2000个请求」。

然而,还有一个问题需要考虑,就是日常的平均负载可能都达不到1000qps。在这种情况下,创建100个连接的连接池会导致资源的浪费。为了避免这种浪费,「我们可以实时统计当前连接池中正在被使用的连接数的pct99的指标值,并使用这个指标值来评估在连接被归还给连接池时是否要释放连接」。这样就可以避免资源的浪费,提高系统的性能和效率。

2.4 连接池满了之后改如何分配连接

当服务负载峰值大于评估值时,连接池就会被耗尽,这个时候如何再分配连接呢?通常有2种策略。

  • 第1种:直接返回失败,无法分配连接,显然这种方式不够友好。
  • 第2种:挂起当前的连接分配请求,并设置一个超时时间。在超时时间内只要有连接被归还给连接池,就唤醒之前被挂起的连接分配请求,尝试分配连接。如果超时时间到了,还没分配到连接,再返回分配连接失败。

显然第2种策略更优,第2种策略尝试了尽最大努力来分配连接。

3.总结

按照春哥上面梳理的思路,我们可以从短连接耗时上涨的量化分析开始,逐步深入到RTT测量、ICMP协议的回显请求、连接保活、连接池大小的评估,以及连接池爆满的异常处理策略。这样的全面分析和深入探讨,必然可以让面试官眼前一亮,让你在众多候选人中脱颖而出。

4.写最后

今天分享的内容就到这里,『如果通过本文你有新的认知和收获,记得关注我,下期分享不迷路,我将持续在掘金上分享技术干货』。

硬核爆肝码字,跪求一赞!!!