Netty「源码分析」之 Idle 检测

简介: Netty「源码分析」之 Idle 检测

前言

在我们启动MyServer之后可以通过TCP连接到我们的Netty服务端, 但是如果我们十秒没有发送消息的话就会自动的失去连接

网络异常,图片无法展示
|

这就是Netty的心跳机制(keepalive), 因为我们在进行TCP连接的时候是占用着服务器资源的, 如果大量连接一直保持着还会造成服务器的宕机

此时此刻心跳机制的作用就体现出来了, 心跳机制能够让服务器及时的释放掉占用的资源

项目来源于本次源码阅读活动, 可以通过下面命令来拉取代码

git clone https://github.com/arthur-zhang/netty-study.git
复制代码

TCPkeep-alive

什么是keepalive, 简单的来讲, 就是客户端和服务端通过TCP来连接, 假设: 客户端突然挂掉了, 由于在这之后客户端和服务端的连接不会再有消息传输, 所以服务端永远不会发现客户端已经挂掉了, 连接会一直保持 , 造成资源浪费

所以在TCP层面引入了keepalive, 假如某一方在规定时间内没有发送探测包或者网络不通之后就会关闭连接, 避免资源的浪费

keepalive 的三个核心参数

TCP中的keepalive核心参数如下所示:

  • tcp_keepalive_time:每次发送心跳的周期, 默认为 7200s
  • tcp_keepalive_intvl:探测包的发送间隔, 默认为 75s
  • tcp_kepalive_probes:在一个心跳周期之内没有接收到对方确认, 继续发送探测包的时间间隔, 默认为 9(次)

keepalive默认是不启动的, 在Netty中, 我们可以通过ServerBootstrap.option(ChannelOption.SO_KEEPALIVE, true)来进行设置

网络异常,图片无法展示
|

有了TCP层面的keep-alive为什么还需要应用层keepalive

TCPkeep-alive只能保证一段时间内连接的两端有数据相互发送, 但是如果碰到网络不佳的情况, 可能会导致心跳收发不及时而断开连接, 这也就是我们为什么需要应用层的keepalive, 也就是空闲检测策略

空闲检测策略: 如果某个连接在规定时间内没有数据流动, 那么就认为该连接是空闲的, 就会将其连接进行关闭. 空闲检测策略在Netty中为我们提供好了, 接下来我们就对其进行详细的讲解

Netty 的 Idle 检测如何实现, 是用 HashedWheelTimer 时间轮吗

还记得我们在前言说的吗, 当我们使用TCP调试工具和Netty服务端连接之后, 如果十秒内没有消息发送的话就会自动的断开连接, 接下来我们从如何配置讲起

Netty 的空闲检测机制配置

Netty中有一个类IdleStateHandler, 这个类是Netty团队为我们准备的的检测连接是否处于空闲状态的双向handler处理器(读和写), 在上篇文章, 我们专门学习过 Netty的六大组件, 其中就有handler相关介绍, 对handler陌生的可以看一下

网络异常,图片无法展示
|

在这个类继承关系图上也可以看到:

  • 该类继承了ChannelDuplexHandler
  • ChannelDuplexHandler即继承了Inbound的入站类, 也继承了Outbound出站类

IdleStateHandler文件中, Netty团队为我们准备的该类对应的实现案例

分析项目中的ServerIdleCheckHandler

接下来我们分析一下在我们的示例项目中是怎么实现Netty的心跳检测机制的

没拉取代码的, 可以通过下述命令拉取代码

git clone https://github.com/arthur-zhang/netty-study.git
复制代码

首先, 我们用ServerIdleCheckHandler类来继承了IdleStateHandler类, 实现ServerIdleCheckHandler()方法和channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt)方法

可以看到这两个方法中都带有Idle单词, 也足以证明这两个方法均和Netty的空闲检测机制有关

网络异常,图片无法展示
|

设置超时时间的构造方法

网络异常,图片无法展示
|

直接点进 super()方法

网络异常,图片无法展示
|

继续往下走就会进入到下面的这个方法

网络异常,图片无法展示
|

可以看到最后就是将几个参数对属性进行赋值罢了, 接下来我们直接说这个方法的作用

我们从构造器开始分析, 直接就可以看到, 我们的空闲十秒断开连接是通过当前类的构造器方法设置的, 两个非0的参数直接肉眼就能看出来了吧, 那么剩下两个参数只能根据名称来判断了

  • readerIdleTime: 读空闲时间, 超过规定时间还没有通过连接读取到数据, 那么就 game over 连接断开
  • 10肯定是十秒了, 也就是
  • writerIdleTime: 写空闲时间, 如果规定时间内没有写数据, 那么连接断开, 为0表示不关心
  • allIdleTime: 读写空闲时间, 如果规定时间内没有读数据或者写数据则连接断开, 0表示不关心
  • unit: 肯定就是时间的单位了
  • TimeUnit.SECONDS肯定是秒

构造器方法执行结束之后, 这个空闲检测的handler就创建好了

初始化操作

经过上面的分析, 在构造方法的过程中, 我们就将心跳给构造好了, 但是我们是在什么时候调用的呢

我们直接去找哪里调用了initialize()相关方法, 别问为什么是这个方法, 问就是未卜先知

网络异常,图片无法展示
|

如上图所示, 根据名称和超简单的判断方法可以判断出分别是以下三种情况会调用initialize()方法, 主要的作用就是保证该初始化方法一定会被触发

  • 连接建立时
  • active事件触发之前
  • active事件已触发, 同时连接建立

initialize() 方法

网络异常,图片无法展示
|

首先可以看到, 这边有个 bug 修复, 即为该类添加了一个标记state属性:

  • 0: 表示已关闭
  • 1: 表示已经开始工作
  • 2: 表示handler已被销毁

网络异常,图片无法展示
|

在早期的Netty中, 如果在任务调度之前关闭了资源会导致NPE空指针异常

initOutputChanged(ctx)方法我们下面在看

ticksInNanos()方法是用来获取纳秒时间的API

网络异常,图片无法展示
|

然后跟了三个启动定时任务的方法schedule

  • 检测读空闲
  • 检测写空闲
  • 检测所有

在这里, 我们可以直接看到它调用的类

网络异常,图片无法展示
|

点进上图三个类中随便的一个类就可以看到这三个类是AbstractIdleTask的实现类, 同时他们都是IdleStateHandler的内部类

网络异常,图片无法展示
|

我们直接看ReaderIdleTimeoutTask的实现run()方法

网络异常,图片无法展示
|

首先, 我们看当前类的变量reading, 可以看到这个变量只有两个地方对其进行了赋值, 我们继续看

网络异常,图片无法展示
|

这两个地方分别是channelRead()方法和channelReadComplete()方法, 这两个方法都是用来判断当前Channel中是否有数据可读, 如果有reading == true, 如果没有数据可读之后会更新上一次的开始读取时间, 同时reading == false

网络异常,图片无法展示
|

所以第一个判断我们解析完了, 如果当前Channel有数据被读到, reading == true则下面判断直接进入else, 重新调度该读空闲检测的定时任务,并更新检测周期

网络异常,图片无法展示
|

如果当前处于读空闲状态, 继续判断是否在指定空闲检测的时间内触发读空闲时间(nextDelay <= 0)

若满足上述条件, 则进入下述流程

网络异常,图片无法展示
|

schedule()方法是一个回调方法, 直接略过

我们会指定到 try 内的newIdleStateEvent()方法, 创建一个新的事件, 最后通过channelIdle(ctx, event);方法将该事件对象回调通知给用户

initOutputChanged(ctx);

这个方法是NettyIdleStateHandler写空闲检测的优化, 默认为 false

网络异常,图片无法展示
|

点进这个属性查看调用情况, 可以看到只有一处调用是给该属性进行赋值操作的

网络异常,图片无法展示
|

兜兜转转, 最后又回到了构造器方法, 有没有感觉到熟悉. 我们最开始就调用了该方法

网络异常,图片无法展示
|

在调用该方法的时候我们默认给这个值传递了 false

网络异常,图片无法展示
|

该方法暂时就分析到这里, 对本次流程并不重要



目录
相关文章
|
3天前
|
算法 Java
Netty新连接接入源码分析(下)
Netty新连接接入源码分析(下)
7 0
|
3天前
|
Java API 索引
Netty新连接接入源码分析(上)
Netty新连接接入源码分析(上)
8 0
|
4月前
|
监控 网络协议 调度
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
Netty Review - 深入探讨Netty的心跳检测机制:原理、实战、IdleStateHandler源码分析
117 0
|
5月前
|
网络协议 调度
Netty心跳检测
客户端的心跳检测对于任何长连接的应用来说,都是一个非常基础的功能。要理解心跳的重要性,首先需要从网络连接假死的现象说起。
|
8月前
|
编解码 前端开发 Java
源码分析Netty:核心组件及启动过程分析
本篇从实例出发,了解Netty核心组件的概念、作用及串联过程。从概念到设计原理,再到深入了解实现细节,从而能够清晰地掌握Netty的技术细节甚至存在的问题,才能最终更好地支持我们实际的各项业务。
314 0
|
Java API 调度
Netty组件EventLoopGroup和EventLoop源码分析
Netty组件EventLoopGroup和EventLoop源码分析
51 0
|
监控 网络协议 Java
Netty源码分析之NIO
Socket是两台主机之间逻辑连接的端点。TCP/IP是传输层协议,定义数据如何在忘了中进行传输。HTTP是应用成协议,主要用来定义规范,包装数据,方便数据处理。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
132 0
|
安全 Java
Netty「源码阅读」之 EventLoop 简单介绍到源码分析
Netty「源码阅读」之 EventLoop 简单介绍到源码分析
172 0
|
网络协议 Java 程序员
Netty源码分析(一) backlog 参数
Netty源码分析(一) backlog 参数
236 0