长连接的心跳及重连设计 (2)

长连接的心跳及重连设计


长连接的心跳及重连设计

这里的 destroy() 方法会把之前开启的定时任务都给取消掉。

所以就不会再有任何的定时任务执行了,也就不会有机会执行这个重连业务

靠谱实现

因此我们得有一个单独的线程来判断是否需要重连,不依赖于 IdleStateHandler。

于是 cim 在客户端感知到网络断开时就会开启一个定时任务:

长连接的心跳及重连设计

之所以不在客户端启动就开启,是为了节省一点线程消耗。网络问题虽然不可避免,但在需要的时候开启更能节省资源。

长连接的心跳及重连设计

长连接的心跳及重连设计

在这个任务重其实就是执行了重连,限于篇幅具体代码就不贴了,感兴趣的可以自行查阅。

同时来验证一下效果。

启动两个服务端,再启动客户端连接上一台并保持长连接。这时突然手动关闭一台服务,客户端可以自动重连到可用的那台服务节点。

长连接的心跳及重连设计


长连接的心跳及重连设计

启动客户端后服务端也能收到正常的 ping 消息。

利用 :info 命令查看当前客户端的链接状态发现连的是 9000端口。

长连接的心跳及重连设计

:info 是一个新增命令,可以查看一些客户端信息。

这时我关掉连接上的这台节点。

kill -9 2142

长连接的心跳及重连设计


长连接的心跳及重连设计

这时客户端会自动重连到可用的那台节点。
这个节点也收到了上线日志以及心跳包。

服务端自动剔除离线客户端

现在来看看服务端,它要实现的效果就是延迟 N 秒没有收到客户端的 ping 包则认为客户端下线了,在 cim 的场景下就需要把他踢掉置于离线状态。

消息发送误区

这里依然有一个误区,在调用 ctx.writeAndFlush() 发送消息获取回调时。

其中是 isSuccess 并不能作为消息发送成功与否的标准。

长连接的心跳及重连设计

也就是说即便是客户端直接断网,服务端这里发送消息后拿到的 success 依旧是 true。

这是因为这里的 success 只是告知我们消息写入了 TCP 缓冲区成功了而已。

和我之前有着一样错误理解的不在少数,这是 Netty 官方给的回复。

长连接的心跳及重连设计

相关 issue:

https://github.com/netty/netty/issues/4915

同时感谢 95老徐以及闪电侠的一起排查。

所以我们不能依据此来关闭客户端的连接,而是要像上文一样判断 Channel 上绑定的时间与当前时间只差是否超过了阈值。

长连接的心跳及重连设计


长连接的心跳及重连设计


长连接的心跳及重连设计

以上则是 cim 服务端的实现,逻辑和开头说的一致,也和 Dubbo 的心跳机制有些类似。

于是来做个试验:正常通信的客户端和服务端,当我把客户端直接断网时,服务端会自动剔除客户端。

长连接的心跳及重连设计


长连接的心跳及重连设计

总结

这样就实现了文初的两个要求。

服务端检测到某个客户端迟迟没有心跳过来可以主动关闭通道,让它下线。

客户端检测到某个服务端迟迟没有响应心跳也能重连获取一个新的连接。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxpwz.html