likes
comments
collection
share

【Netty】「项目实战」(二)提升聊天室的性能,从引入心跳检测机制开始

作者站长头像
站长
· 阅读数 22

前言

本篇博文是《从0到1学习 Netty》中实战系列的第二篇博文,主要内容是通过引入心跳检测机制来解决假死连接问题,避免资源浪费和通信失败,往期系列文章请访问博主的 Netty 专栏,博文中的所有代码全部收集在博主的 GitHub 仓库中;

假死连接

在上一篇博文 如何构建多客户端聊天室 中,我们构建了一个简易的聊天室 demo,然而它还有许多需要优化的地方,本篇博文要讲的是如何及时检测和处理假死连接,减少资源浪费。

那什么是假死连接呢?假死连接是指在网络通信中出现的一种状态,其中连接看似正常但实际上已经失效。

这种情况可能由以下原因引起:

  1. 网络设备故障:例如网卡、机房等底层设备发生故障,导致 TCP 连接断开。尽管底层连接已经断开,但应用程序没有察觉到,并继续占用资源。
  2. 不稳定的公网网络:如果公网网络存在丢包问题,连续丢包会导致客户端数据发送失败,服务端也无法接收数据,从而造成资源浪费。
  3. 应用程序线程阻塞:应用程序线程可能由于某些原因而被阻塞,无法进行数据的读写操作,这会导致连接状态僵化,表面上看连接正常但实际上无法传输数据。

与假死连接相关的问题包括:

  1. 无法自动释放占用的资源:由于应用程序未能正确检测到连接状态的变化,假死连接会持续占用系统资源,造成资源浪费。
  2. 发送超时:当向假死连接发送数据时,由于连接已失效,无法成功发送数据,导致发送操作超时。

在 Netty 中会使用处理空闲状态的处理器 IdleStateHandler 来对假死连接进行及时检测,并触发相应的事件。空闲状态指的是连接或通道在一段时间内没有进行读取、写入或者读写操作的情况。

空闲检测

IdleStateHandler 的作用是监测连接或通道的空闲状态,并在达到指定的空闲时间阈值时触发相应的事件。通过使用 IdleStateHandler,我们可以轻松地检测和处理空闲连接或通道,以便执行特定的操作或者维护连接的健康状态。

【Netty】「项目实战」(二)提升聊天室的性能,从引入心跳检测机制开始

IdleStateHandler 可以根据需要设置三种类型的空闲状态:

  1. 读空闲 READER_IDLE:当在指定的时间段内没有从连接中读取到数据时,就会触发读空闲事件;
  2. 写空闲 WRITER_IDLE:当在指定的时间段内没有向连接中写入数据时,就会触发写空闲事件;
  3. 读写空闲 ALL_IDLE:当在指定的时间段内既没有读取到数据,也没有写入数据时,就会触发读写空闲事件。

当指定时间内未发生读或写事件时,会触发特定事件,代码如下所示:

ch.pipeline().addLast(new IdleStateHandler(0, 0, 60));  
ch.pipeline().addLast(new ChannelDuplexHandler() {  
    @Override  
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                ctx.close();
            } else if (e.state() == IdleState.WRITER_IDLE) {
                ctx.writeAndFlush(new PingMessage());
            }
        }
    }  
});

在上面的示例中,我们将 IdleStateHandler 添加到通道的管道中,并设置了读写都空闲的时间阈值为60秒。当连接或通道60秒内没有读取或写入操作时,IdleStateHandler 会触发 IdleStateEvent 事件。

为了方便展示,将 IdleStateHandler 设置为如果5秒内未读到数据,则会触发 READ_IDLE 事件,如下所示:

【Netty】「项目实战」(二)提升聊天室的性能,从引入心跳检测机制开始

接下来,我们根据上述原理,实现心跳检测机制。

心跳机制

心跳检测机制是一种常用的网络通信机制,用于检测通信双方是否保持连接。它的基本原理是,一方定期向另一方发送一个特殊的数据包,称为心跳包,如果在一定时间内没有收到回复,就认为对方已经断开。心跳检测机制可以用于检测网络故障,释放资源,或者尝试重连。

为了确保心跳机制的有效性,需要设置合适的心跳频率。通常情况下,服务器会设置一个 IdleTimeSeconds 参数,表示服务器在多长时间内没有收到客户端的任何消息时将视为 READ_IDLE 事件。为了避免此类情况的发生,客户端发送心跳包的频率应小于服务器设置的 IdleTimeSeconds 值。一种常见的做法是将心跳频率设置为 IdleTimeSeconds 的一半,以确保在服务器认定客户端处于空闲状态之前,客户端已经发送了新的心跳包。

// 服务端
ch.pipeline().addLast(new IdleStateHandler(60, 0, 0));

// 客户端
ch.pipeline().addLast(new IdleStateHandler(0, 30, 0));

运行结果:

【Netty】「项目实战」(二)提升聊天室的性能,从引入心跳检测机制开始

通过实施心跳机制,可以有效地处理非网络相关的 READ_IDLE 事件。它可以提供及时的反馈,确保服务器和客户端之间的连接保持活跃,同时减少不必要的断开连接操作,提升系统的稳定性和用户体验。

后记

总而言之,通过引入心跳检测机制,我们成功地提升了聊天室的性能。通过定期发送心跳包,服务器可以持续监测与客户端的连接状态。一旦发现某个连接长时间没有响应,服务器会立即采取相应措施,如关闭该连接或重新建立连接,以确保聊天室的稳定性和可靠性。

以上就是 提升聊天室的性能,从引入心跳检测机制开始 的所有内容了,希望本篇博文对大家有所帮助!

参考:

📝 上篇精讲:「项目实战」(一)如何构建多客户端聊天室

💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注,创作不易,请多多支持;

👍 公众号:sidiot的技术驿站

🔥 系列专栏:探索 Netty:源码解析与应用案例分享

转载自:https://juejin.cn/post/7249651027745931301
评论
请登录