转转微服务框架的连接管理

转转RPC框架SCF(Service Communication Framework)继承自58集团RPC框架,在转转经历多版本的迭代及重构。作为一款网络应用,连接在其中占据重要地位,转转SCF在连接管理上做了大量的优化与功能新增。本文以连接的生命周期为主线谈谈RPC框架连接管理的具体实现。

1 连接的建立时机

RPC框架客户端通过动态代理机制实现和本地方法调用同样的体验。从创建代理到发起调用还需要经过从注册中心发现节点、建立连接两个步骤。SCF支持立即发现/延迟发现节点,立即建立/延迟建立连接,可通过参数配置。

如果应用在启动时创建代理类,立即发现节点、立即建立连接可减少初次请求的耗时,避免请求超时。而延迟发现节点、延迟建立连接则会导致初次请求耗时加长,有可能造成请求的超时。

延迟发现节点主要是为了解决服务的循环依赖问题,虽然服务的循环依赖是个坏味道,但现实中仍难以完全避免。例如有服务A、B互相依赖,如果服务A、B都未部署,且未配置延迟发现参数,则A、B都无法部署成功,均会抛出无服务节点可用异常。

延迟发现节点和延迟建立连接虽然会导致初次请求耗时加长,但是在某些场景下可以提升效率。例如单个接口测试场景下,并不需要连接所有依赖服务,仅需发现并连接测试接口所依赖的服务即可,缩短服务启动时间,提升测试效率。

2 需要多少条连接

2.1 连接池

连接池的概念想必各位读者都不陌生,数据库连接池、Redis连接池、HTTP连接池等。使用连接池的其中一个目的是为了连接的复用。为什么要复用连接呢,因为建立TCP连接是个重量级操作,不仅3次握手消耗时间,而且需要操作系统为连接分配文件描述符和缓冲区。

使用连接池的另外一个重要目的是提升并发数,可以在多条连接上并发地发起请求。并发地发起请求为什么需要使用多条连接呢,单条连接无法实现吗还是受制于单连接的带宽限制呢。单条连接无法并发地发起请求的主要原因是应用层协议限制。以HTTP1.1为例,如下图所示,协议要求在一条连接上只能有一个未完成的请求,也就是说HTTP1.1协议要求客户端在接收到上一个HTTP响应之后才能发起下一个HTTP请求。为什么会有这样的协议要求呢,因为请求和响应是一一对应的,如果不遵守这个协议,有可能先发出的请求耗时比较长,后返回,而后发出的请求耗时比较短,先返回,这样就造成了请求和响应的错乱。
http1.1协议
为了提升这种请求-响应-请求-响应协议的的性能,有些协议支持了管线化(PipeLine),比如Redis。管线化支持同时发起多个请求,但是响应的顺序仍然需要和请求的顺序保持一致,如下图所示。管线化优化了网络性能,可以减少一些网络开销,但是仍然解决不了队头阻塞问题,要想提高并发数量,仍需要使用多条连接。事实上HTTP1.1也支持管线化,只是平时很少接触罢了,因为HTTP协议常用于前后端通信场景,对耗时的容忍度比较高,管线化请求未得到大规模使用。
Pipeline

2.2 多路复用

在同一条TCP连接上并发地发起请求,也就是连接的多路复用,需要协议的支持,在应用层协议需要使用requestId或其他类似的概念将请求和响应一一对应起来,有了requestId的支持请求和响应就可以在连接上乱序发送了。

例如HTTP2.0使用streamId将请求和响应对应起来,HTTP2.0的通信模型如下图所示。HTTP2.0允许将同一个请求/响应拆分成不同的帧,到达应用之后再组合成完整的请求/响应,所以图中出现了重复了StreamId。
HTTP2.0

转转RPC框架的协议设计思路同HTTP2.0类似,只是不允许将请求/响应拆分成多帧,如下图所示。
SCF-多路复用
在协议支持多路复用的情况下,连接池就可以被淘汰了,默认情况下SCF客户端与服务端只建立一条TCP连接。如果需要传输的数据量比较大,可以通过参数设置更多连接数量,此时虽然有多条连接,但是这仍然与连接池有着本质的不同。连接池内的多条连接有借出与归还的概念,已经借出的连接不会被其他请求使用。而多路复用下的多条连接没有借出与归还的概念,同一条连接仍然可以被多个请求共同使用。

在协议支持多路复用的情况下,单条连接上请求和响应完全可以是乱序的,如下图所示。
多路复用-请求响应

3 连接保活

3.1 TCP保活机制

保活并不是TCP规范的一部分,理由是:(1)在出现短暂差错的情况下,这可能会使一个非常好的连接释放掉;(2)耗费不必要的带宽;(3)在按分组计费的情况下会在互联网上花掉更多的钱。然而,许多实现提供了保活功能。这说明保活是一个有争论的功能,许多人认为保活功能不应该由TCP提供,而应该由应用程序来完成。——TCP/IP详解卷1,谢希仁

在建立TCP连接时可以通过SO_KEEPALIVE参数来指定是否开启TCP保活功能,一般情况下TCP层的默认保活时间是2个小时,保活时间参数是操作系统级别的参数,无法对单独的TCP连接设置。

3.2 应用层保活

转转RPC框架提供了应用层保活机制,虽然TCP实现上提供了保活机制,但是TCP的保活时间太长(默认2小时)无法及时发现不健康的连接。

SCF客户端使用两个参数readerIdleTime(默认3秒)和idleTimeout(默认10秒)来进行保活控制。如果一条连接上超过readerIdleTime时间未发生读事件,则认为该连接为idle状态。如果一条连接上超过idleTimeout时间未发生读事件,则关闭连接。idle状态的检测与事件触发使用Netty提供的IdleStateHandler完成。转转RCP框架底层使用Netty通信,Handler的排列如下。
scf-pipeline
IdleStateHandler仅提供了在连接为idle状态时触发IdleStateEvent的能力,判断连接的健康状态仍需要获取连接上的idleTime。在BizHandler中发生channelActive事件或者channelRead事件时使用Channel提供的属性功能将Channel的lastReadTime属性设置为当前时间,即记录该连接上最后一次读事件的发生时间。在收到IdleStateEvent时,首先获取连接的lastReadTime属性,如果lastReadTime和当前时间的时间差未超过idleTimeout则在连接上发送心跳请求,在连接健康的情况下服务端收到心跳请求后回复心跳响应,lastReadTime得以更新。在连接不健康的情况下,服务端无法收到心跳请求或者客户端无法收到心跳响应,lastReadTime得不到更新,在后续的某次IdleStateEvent触发时,lastReadTime与和当前时间的差值超过idleTimeout则关闭连接。

SCF服务端默认的readerIdleTime为20秒,在收到客户端发来的心跳请求时,回复心跳响应,而收到IdleStateEvent时关闭连接。

一条健康的连接,心跳时序图如下图所示。
healthy-connection
一条不健康的连接,心跳时序图如下图所示。
unhealth-connection

4 自动修复

保活机制可以及时发现并关闭不健康的连接,但是连接的不健康原因有多种。常见的如网络故障、机器宕机、GC等。如果故障修复完成或者应用从GC中恢复过来,需要重新建立连接。

SCF客户端为每一条连接添加一个定时任务每5秒钟检测连接的状态,如果发现连接断开,则尝试重连。

5 优雅关闭

Netty服务端IO线程分为bossEventLoopGroup(线程组)和workerEventLoopGroup(线程组),bossEventLoopGroup负责监听端口及新连接的建立,连接建立后交给workerEventLoopGroup处理。

服务端的优雅关闭首先要关闭bossEventLoopGroup以拒绝新的连接。
在这里插入图片描述
然后向所有的现有连接发送关闭事件,但是并不立即关闭连接,因为已经建立的连接上可能还有未处理的请求。
在这里插入图片描述
客户端在收到服务端发送的关闭事件之后首先将状态设置为关闭中,以避免新的请求负载到该连接上。
在这里插入图片描述
同时开启定时任务每秒检测连接上剩余未返回的请求数量和获取连接的writerIdleTime,如果writerIdleTime超过了静默时间并且未返回的请求数量为0,则关闭连接。之所以不能仅仅以未返回的请求数量为0就关闭连接,是因为在将状态设置为关闭中之后,可能有线程正在执行负载均衡之后到发送数据之前的代码,需要为这段代码的执行设置静默时间。
在这里插入图片描述

服务端在向所有的连接发送关闭事件之后,每隔一秒检测一次剩余的连接数量,等到连接数量为0时关闭workerEventLoopGroup。
在这里插入图片描述

6 总结

本文详细介绍了转转RPC框架SCF的连接管理,包括连接的建立时机、连接数量、保活、自动修复、优雅关闭。
其中的重点在于对于连接数量的思考和优雅关闭,希望对读者在自行设计协议时能有所帮助。


关于作者

王建新,转转架构部服务治理负责人,主要负责服务治理、RPC框架、分布式调用跟踪、监控系统等。爱技术、爱学习,欢迎联系交流。

转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。

关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值