23

TCP长连接及连接管理探讨

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUxMDk2MTAyMA%3D%3D&%3Bmid=2247484654&%3Bidx=1&%3Bsn=56280f39d8cd37d9bb87cd90846c5079
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP生命周期分为三个阶段: 建立连接、传输数据、关闭连接。 根据使用方法不同,可认为TCP连接分长连接和短连接。 如果每次通信后就close掉连接,那TCP就相当于短连接。 如果请求结束后保持TCP连接的状态不关闭,那TCP就是长连接。

一、为什么使用长连接

  • TCP连接的建立需要3次握手,断开需要4次挥手。 使用长连接可以减少连接的建立次数,减少CPU及内存的使用

  • 实现pipelining模式

7bEbiii.png!web

  • 实现服务端push数据给客户端

  • 减少TCP请求,减少网络堵塞

  • 减少后续请求的响应时间

  • 减少了三次握手和四次挥手的时间

单线程1000次请求数据对比:

  • TCP 短连接用时:4.6s

  • TCP 长连接用时:2.5s

二、长连接会有什么问题

维护成本高,随着服务的运行,建立的连接会越来越多,最终可能导致服务器不堪重负。因此如何管理连接和清理死连接(不活跃)就显得尤为重要。

(1)心跳检测

  • TCP 层:KeepAlive机制

  • 应用层:心跳

TCP keepalive机制

NfmMFj6.png!web

  • tcp keepalive time:在链路上没有数据传送的情况下,tcp keepalive time秒后触发tcp心跳

  • tcp keepalive intvl:心跳每个tcp keepalive intvl秒发送一次

  • tcp keepalive probes:发送tcp keepalive probes次都无响应后将断开连接

KeepAlive本质

通过抓包数据来看,是 TCP 发送一个数据长度为0的空包,ack最后一个包的序号,这样对应用层无影响。

默认情况下,是关闭 TCP 的KeepAlive机制的。

go打开KeepAlive的方法:

(2)连接管理

目前主要有2种连接管理方式:

  • 基于 ip:port 的连接池

    ip:port为key,缓存一组连接

  • 基于 seq 的连接池管理

    需要应用层协议支持,客户端在请求包中加入seq,收到返回包后根据seq找到相应的回调方法。

连接池

bingo服务端使用的tcp层keepalive机制检查连接状态,同时服务端支持pipeline的方式处理请求。因此在客户端可以使用连接池来复用 TCP 长连接,避免客户端创建大量的连接。

常见实现方式:

  • map+chan

  • map+list

使用 map + chan的方式实现

fai6F3F.png!web

  • conn pool:负责管理conn set

  • conn set:一个ip:port拥有一个conn set,负责申请连接、释放连接的具体实现,使用chann缓存连接

2个参数&2个方法

vqQb2uI.png!web

  • maxIdleSize:一个ip对应的最大空闲连接数。等于channel的大小

  • maxIdleTime:最大空闲时间,连接超过这个时间可认为是不活跃连接,可以直接关闭

  • Alloc:申请一个连接

  • Reclaim:把连接返回连接池,连接在使用过程中若发生error,则应该close掉连接,不应该把该连接返回连接池

申请连接时,会优先从连接池中获取链接,如果获取失败或尝试次数达到上限后才会创建新连接。

Zfa2eaM.png!web

数据对比

(1)不使用连接池

  • 单协程请求总数:100

  • 请求间隔时间:0~50ms

  • 协程数:500

  • 成功:51636

  • 失败:3364

  • 端口占用:50000

(2)使用连接池

  • 单协程请求总数: 500

  • 请求间隔时间: 0~50ms

  • 协程数: 50

  • 成功: 50000

  • 失败: 0

  • 端口占用: 5~10

优点:

1.代码实现比较简单。

2.上层协议无关,任何协议都可以接入连接池。

缺点:

  1. 高并发下占用过多的fd。

  2. 如果请求间隔时间为0,占用端口数=协程数。

基于seq的连接池管理

这种方式通常用于异步rpc调用

FNNfq2q.png!web

客户端会缓存seq->channel(存放返回包、用于回调),

客户端发包在包头中填写seq值,服务端会将seq字段原封不动的带回来,

然后通过seq查找到对应的channel,将数据放进去。等待数据的协程就可以接着处理请求了。

这种方式管理连接,通常发送请求包和接受返回包是不同的进程(写成),通过map 来共享数据,完成回调等操作。

jungle中返回包处理代码:

reAnmqr.png!web

交互流程

INJfA37.png!web

如果conn本身是协程(进程)安全的,在alloc连接时,连接池可以不把此连接清除掉。这种情况下连接池的主要作用是根据策略做连接的负载均衡。

优点:

  1. 连接复用,理论上一个ip+port可以只对应一个连接。

  2. 基于seq复用,节省fd。

缺点:

  1. 实现复杂,异常状态多,超时、连接断开不可用等处理逻辑复杂。

  2. 需要应用层协议支持。

TCP长连接相对短连接,传输速度快,可是实现一些高级功能,如:server可以主动发送数据给client。但是需要服务端维护连接,增加系统的复杂性。保持的连接也会占用和多系统资源,带来更多的风险。因此具体选择哪种技术,还需要根据具体情况做权衡。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK