RPC学习系列(二)--对RPC长连接维护的理解
最近在用Netty做毕设,写的是一个MQTT服务器,需要维护长连接。之前写过一个简单的rpc,想起了连接的实现(用的短链接)。加上春招面试被问到了rpc长连接方面的内容,所以打算来写一篇水文。
关键字:rpc长连接,tcp长连接,保活。
前言
谈到RPC肯定绕不开TCP通信,而主流的Java RPC框架都依赖于Netty等通信框架,这时候我们还要考虑是使用长连接还是短连接:
- 短连接:每次通信结束后关闭连接,下次通信需要重新创建连接;优点就是无需管理连接,无需保活连接;
- 长连接:每次通信结束不关闭连接,连接可以复用,保证了性能;缺点就是连接需要统一管理,并且需要保活;
主流的RPC框架都会追求性能选择使用长连接,所以如何保活连接就是一个重要的话题,也是本文的主题,下面会重点介绍一些保活策略;
为什么需要保活
上面介绍的长连接、短连接并不是TCP提供的功能,所以长连接是需要应用端自己来实现的,包括:连接的统一管理,如何保活等;
Q1. 如何保活之前我们了解一下为什么需要保活?
主要原因是网络不是100%可靠的,我们创建好的连接可能由于网络原因导致连接已经不可用了,如果连接一直有消息往来,那么系统马上可以感知到连接断开;
但是我们系统可能长时间没有消息来往,导致系统不能及时感知到连接不可用,也就是不能及时处理重连或者释放连接;常见的保活策略使用心跳机制由应用层来实现,还有传输层提供的TCP Keepalive保活探测机制;
TCP Keepalive机制
TCP Keepalive是操作系统实现的功能,并不是TCP协议的一部分,需要在操作系统下进行相关配置,开启此功能后,如果连接在一段时间内没有数据往来,TCP将发送Keepalive探针来确认连接的可用性,Keepalive几个内核参数配置:
- tcp_keepalive_time:连接多长时间没有数据往来发送探针请求,默认为7200s(2h);
- tcp_keepalive_probes:探测失败重试的次数默认为10次;
- tcp_keepalive_intvl:重试的间隔时间默认75s;
以上参数可以修改到/etc/sysctl.conf文件中;
Q2. 是否使用Keepalive用来保活就够了?
其实还不够,Keepalive只是在网络层就行保活,如果网络本身没有问题,但是系统由于其他原因已经不可用了,这时候Keepalive并不能发现;所以往往还需要结合心跳机制来一起使用;
心跳探活机制
何为心跳机制,简单来讲就是客户端启动一个定时器用来定时发送请求,服务端接到请求进行响应,如果多次没有接受到响应,那么客户端认为连接已经断开,可以断开半打开的连接或者进行重连处理;
flag:研究下Dubbo、grpc是如何具体实施的;
个人理解:
双端都发送心跳请求,所以可以发现有两个时间点分别是:lastRead和lastWrite;当然时间和最后读取,最后写的时间间隔大于heartbeat就会发送心跳请求;
如果多次心跳未返回结果,也就是最后读取消息时间大于heartbeatTimeout会判定当前是Client还是Server。如果是Client会发起reconnect,如果是Server则会close关闭连接,等待客户端重连。这样的考虑是合理的,客户端调用是强依赖可用连接的,而服务端可以等待客户端重新建立连接;
一般探活策略都是,隔多长时间探活几次,几次内无响应,主动探活的一方则关闭连接,释放资源。
总结
-
本文首先介绍了RPC中引入的长连接方式的初衷,继而引出长连接的保活机制,为什么需要保活?
-
然后分别介绍了网络层保活机制TCP Keepalive机制,应用层心跳机制;
-
应用层心跳保活实现思路,双方定时器探活
- 客户端心跳对连接定时探活,每隔多少时间探活多少次无果,则reconnect
- 服务端心跳对连接定时探活,每隔多少时间探活多少次无果,则close
- 原文作者:devhg
- 原文链接:https://ihui.ink/post/rpc/02-keep-alive/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。