【TCP长连接】使用TCP长连接提升服务性能

时间:2024-03-23 08:32:12

1、概述

在《性能优化篇-理论基础》中,我们知道了提升服务性能的两个思路,分别是提升服务并发能力和降低请求的响应时间(RT)。一个请求的响应时间包括两部分,等待时间和执行时间。在《性能优化篇-减少网络传输包提升服务性能》中分析了如何减少网络包的传输来降低响应的等待时间,从而提升服务的性能。本文继续从网络通信方面来描述如何通过长连接来提升服务性能。

2、为什么长连接可以提升服务性能

在TCP/IP协议中,传输层负责应用程序之间的网络通信数据的传输,传输层协议主要有UDP和TCP。UDP协议是面向无连接的,可以随时发送数据,但是TCP协议是面向有连接的,只有在确认通信接收端存在的情况下才会发送数据,并且在连接断开时也会确认另一方是否还需要发送数据,这就是TCP协议的三次握手和四次挥手,如下图所示:

【TCP长连接】使用TCP长连接提升服务性能

TCP 连接建立和断开流程示意图

如果你的网络应用服务使用的是TCP传输协议,那么每当客户端和服务端传输数据之前,都需要先进行TCP的3次握手,传输完毕后又要进行四次挥手,示意图如下所示,客户端和服务端交互数据只使用了2次网络传输,而建立和断开连接却使用了7次网络传输,如果发送端和接收端之间频繁发送小的数据包,则可能会出现建立和断开连接的开销比发送数据的开销还要大。此外,每次在发送数据前,都需要等待连接的建立,也会增加数据发送的等待时间。

【TCP长连接】使用TCP长连接提升服务性能

所以针对客户端和服务端需要频繁发送数据的场景,可以使用长连接的方式提升服务性能,即发送方和接收方建立连接后,保持连接不断开,下次需要发送数据时可以直接使用已经建立的TCP连接发送数据,而无需等待。

虽然长连接可以提升服务的性能,但是因为网络环境的复杂性,连接建立后可能会因为各种原因被强制断开,因此在建立长连接后必须使用心跳探测等方式来检测连接的可用性,这在一定程度上增加了开发和维护成本。此外,由于每个网络连接都会占用一定的内存资源,针对服务端而言,如果大量客户端与服务端在首次发送完数据后便在很长一段时间内处于空闲状态,那么将白白浪费服务端大量的资源。笔者在实际业务中便遇到了这种问题,需要对空闲连接进行监测,如果长时间没有发送有效数据包,则服务端主动断开连接。

因为服务端能承受的连接数是有限的,在Linux系统下每个TCP连接都是一个文件句柄,因此长连接数量首先受到文件句柄大小限制,其次每个连接都会占用一定的内存资源,所以使用长连接还会面临着更严峻的安全问题,比如非法客户端通过脚本的方式不断与自身服务端建立长连接,当连接资源被耗尽的时候,有效的客户端连接无法建立。可以通过TLS的双向校验解决这个问题,也可以客户端和服务端约定连接的安全协议,建立连接后进行安全认证,服务端一旦发现认证失败的连接,则立即断开连接。

3、长连接提升服务性能的实际应用

3.1、http协议长连接的应用

http协议是应用层协议,在传输层使用TCP协议,因此使用长连接依然可以减少TCP连接建立和断开带来的CPU开销和等待时间。由于http是请求-响应协议,因此在http1.0的时候,客户端每次向服务端发送一次http请求都会重新建立一个TCP连接,收到服务端的http响应后就会断开http连接,因此可以认为是使用的“短连接”。在http1.1版本以后,会在http请求的header中添加“Connection:Keep-Alive”来告知服务端发送完响应后维持这个TCP连接不断开,服务端会通过“Keep-Alive: timeout=20”来告知客户端,服务端会维持这个长连接的时间,如果客户端不再发送数据,也可以通过“Connection: Close”主动告知服务端断开连接。

【TCP长连接】使用TCP长连接提升服务性能

http响应头信息

http2.0版本不仅仅使用TCP的长连接,而且还升级为复用此长连接,解决了http的请求-响应串行执行的问题。

【TCP长连接】使用TCP长连接提升服务性能

3.2、websocket协议长连接的应用

websocket协议是在单个TCP连接上建立的全双工的通信协议,于2011年被IETF定为标准RFC 6455,也是应用层协议。与http不同的是,websocket不再是请求-响应模式,而是服务端也可以向客户端主动推送消息。其目的是解决http协议只能客户端发送请求,服务端应答的模式在即时消息等场景下存在的问题,因此客户端和服务端完成一次握手后,两者之间就直接可以创建TCP长连接,并进行双向数据传输,该连接会持续到任何一端主动断开TCP连接。

因为websocket协议从出生之时就考虑的是使用TCP的长连接,而不像http1.1是将http1.0短连接升级为长连接,因此websocket协议从制定时就省去了状态码,header这些额外的信息(如Content-Type、Accept等),因此减少了网络包传输的大小,通过《性能优化篇-减少网络包大小提升服务性能》可知,减少网络包大小可以进一步提升服务性能。

笔者所在的业务,因为涉及到即时消息,在项目中使用了websocket,相比于http会大大降低客户端请求的响应时间,但是websocket与http的长连接不一样,websocket在握手完毕后建立的是永久的TCP长连接,而http通过服务端来控制长连接的持续时间,通过Keep-Alive头信息告知客户端,因此如果实际业务中使用websocket的话,要注意第2节中提到的长连接面临的问题。

3.3、开源框架中长连接的应用

在大型网站中,rpc框架dubbo、消息队列中间件rocketMq等都在大量使用,这些中间件为了提升服务性能,在客户端和服务端之间也使用的是长连接。

首先看一下dubbo框架,consumer与provider之间便使用的是TCP长连接,对于RPC框架来说,长连接对于性能的提升起到了非常大的作用,因为consumer和provider之间将会存在频繁的数据传输,如果使用短连接的话,每次都有进行3次握手和4次挥手,不仅增加了数据传输的等待时间,同时consumer和provider在连接建立和断开的开销上也将占用较多的CPU资源

【TCP长连接】使用TCP长连接提升服务性能

在rocketMq中,producer、consumer和broker之间也是建立的长连接,其实原因跟dubbo类似,producer、consumer和broker之间会存在频繁的数据交互,因此使用长连接可以减少等待时间和cpu的开销。

【TCP长连接】使用TCP长连接提升服务性能

不管是dubbo还是rocketmq,因为其客户端不会像web网站这样面临着几十万甚至上百万的长连接,其客户端数量必定十分有限,因此使用长连接也不会占用服务端过多的内存资源,但是却对性能的提升起到了极大的帮助,因此在实际业务开发中,比如你所在的业务也有类似dubbo、rocketMq这种业务场景,不妨考虑直接使用长连接。

4、总结

在TCP/IP协议中,由于TCP是面向连接的传输层协议,因此在连接建立时存在3次握手,连接断开时存在4次挥手,虽然3次握手和4次挥手是TCP可靠传输网络包的基础,但是也对性能产生了一定的影响,增加了请求的等待时间。如果在实际业务中,发送方和接收方之间存在频繁的数据交互,不妨像文中提到的场景一样,考虑使用长连接来避免连接的频繁建立和断开,以提升服务的性能。

 

 

Socket长连接和短连接

1概念

Socket:socket实际上是对TCP/IP进行的封装,我们可以使用socket套接字通过socket来传输。首先我们需要明白的一个概念就是通道,简单地说通道就是两个对端可以随时传输数据的信道。我么常说的所谓建立socket连接,也就是建立了客户端与服务器端的通道。

长短连接:显而易见,长连接也就是这个socket连接一直保持连接,也就是通道一直保持通畅,两个对端可以随时发送和接收数据;短连接就是我们发送一次或有限的几次,socket通道就被关闭了。首先,我们必须明白的是socket连接后,如果没有任何一方关闭,这个通道是一直保持着的,换句话说,如果任何一方都不关闭连接,这个socket连接就是长连接,因此Java中的socket本身就是支持长连接的(如一个简单的实验:服务器端不关闭连接,服务器端每隔10秒发送一次数据,服务器端每次都能正确接受数据,这个实验就可以证明)。

那么既然socket本身是支持长连接的,那么为什么我们还要提短连接的概念呢?试想一个中国移动的短信网关(即通过发布socket通信接口)每时每分都有N多个连接发送短信请求,加入服务器不加任何限制地直接和客户端使用长连接那么可想而知服务器需要承受多么大的压力。所以一般的socket服务器端都是会设定超时时间的,也就是timeout,如果超过timeout服务器没有接收到任何数据,那么该服务器就会关闭该连接,从而使得服务器资源得到有效地使用。

2 如何实现长短连接

在1中我们已经介绍了长短连接的概念,服务器如果超过timeout时间接收不到客户端的通信就会断开连接,那么假如客户端在timeout时间前一秒(或者更短的时间)发送一条**数据来使服务器端重新计时,如此重复就能保证服务器一直不能进入timeout时间,从而一直保持连接,这就是长连接的实现原理。下面我们通过一张图说明:

【TCP长连接】使用TCP长连接提升服务性能

由上图可见,是否是长连接完全取决于客户端是否会在timeout时间发送心跳消息,因此长短连接是和客户端相关的,服务器端没有任何区别(只不过服务器端需要设定timeout而已)。