Netty心跳检测
文章目录
- 一、网络连接假死现象
- 二、服务器端的空闲检测
- 三、客户端的心跳报文
客户端的心跳检测对于任何长连接的应用来说,都是一个非常基础的功能。要理解心跳的重要性,首先需要从网络连接假死的现象说起。
一、网络连接假死现象
什么是连接假死呢?如果底层的TCP连接已经断开,但是服务器端并没有正常地关闭套接字,认为这条连接仍然是存在的。
连接假死的具体表现如下:
- 在服务器端,会有一些处于TCP_ESTABLISHED状态的正常连接
- 在客户端,TCP客户端已经显示连接已经断开
- 客户端此时虽然可以进行断线重连操作,但是上一次连接状态依然被服务器端认为有效,并且服务器端的资源得不到正确释放,包括套接字上下文以及接受/发送缓冲区
连接假死的情况虽然不常见,但是确实存在。服务器端长时间运行后,会面临大量假死连接得不到释放的情况。由于每个连接都会消耗CPU和内存资源,因此大量假死的连接会逐渐耗光服务器的资源,使得服务器越来越慢,IO处理效率越来越低,最终导致服务器崩溃。
连接假死通常是由多个原因造成的:
- 应用程序出现线程堵塞,无法进行连接的读写
- 网络相关的设别出现故障
- 网络丢包
解决假死的有效手段是客户端定时进行心跳检测,服务端定时进行空闲检测。
二、服务器端的空闲检测
想解决假死问题,服务器端的有效手段是空闲检测。所谓空闲检测就是每隔一段时间监测子通道是否有数据读写,如果有则子通道是正常的,如果没有则判定为假死,关闭子通道。
服务器端实现空闲检测只需要使用Netty自带的IdleStateHandler空闲状态处理器就可以实现这个功能。
@Slf4j
public class HeartBeatServerHandler extends IdleStateHandler {private static final int READ_IDLE_GAP = 150; // 最大空闲时间(s)public HeartBeatServerHandler() {super(READ_IDLE_GAP, 0, 0, TimeUnit.SECONDS);}@Overrideprotected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {log.info("{}秒内未读到数据,关闭连接", READ_IDLE_GAP);// 其他处理,如关闭会话}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 判断消息实例if (!(msg instanceof MessageProtos.Message message)) {super.channelRead(ctx, msg);return;}if (message.getType() == MessageProtos.HeadType.HEART_BEAT) {if (ctx.channel().isActive()) {// 将心跳数据包直接回给客户端ctx.writeAndFlush(msg);}}super.channelRead(ctx, msg);}
}
在HeartBeatServerHandler的构造函数中,调用了基类IdleStateHandler的构造函数,传递了四个参数:
- 入站空闲检测时长:指的是一段时间内如果没有消息入站就判定为连接假死
- 出站空闲检测时长:指的是一段时间内如果没有数据出站就判定为连接假死
- 出/入站检测时长:表示在一段时间内如果没有出站或者入站就判定为连接假死
- 时间单位
判定为假死之后IdleStateHandler会回调自己的channelIdle()方法,一般在这个方法中去进行一些连接的关闭。
HeartBeatServerHandler实现的主要功能是空闲检测,需要客户端定时发送心跳数据包(或报文、消息)进行配合,而且客户端发送心跳数据包的时间间隔需要远远小于服务器端的空闲检测时间间隔。
收到客户端的心跳数据包之后可以直接回复客户端,让客户端也能进行类似的空闲检测。由于IdleStateHandler本身是一个入站处理器,只需要重写这个子类的channelRead方法,然后将心跳数据包直接写回给客户端即可。
如果HeartBeatServerHandler要重写channelRead方法,一定要调用积累的channelRead方法,不然IdleStateHandler的入站空闲检测会无效。
三、客户端的心跳报文
与服务器端的空闲检测相配合,客户端需要定期发送数据包到服务器端,通常这个数据包称为心跳数据包。
@Slf4j
public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {// 心跳的时间间隔,单位为秒private static final int HEART_BEAT_INTERVAL = 50;// 在Handler业务处理器被加入到流水线时开始发送心跳数据包@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {ClientSession session = ctx.channel().attr(ClientSession.CLIENT_SESSION).get();MessageProtos.MessageHeartBeat heartBeat =MessageProtos.MessageHeartBeat.newBuilder().setSeq(0).setJson("{\"from\":\"client\"}").setUid(session.getUserDTO().getUserId()).build();MessageProtos.Message message = MessageProtos.Message.newBuilder().setType(MessageProtos.HeadType.HEART_BEAT).setSessionId(session.getSessionId()).setMessageHeartBeat(heartBeat).build();heartBeat(ctx, message);super.handlerAdded(ctx);}private void heartBeat(ChannelHandlerContext ctx, MessageProtos.Message message) {// 提交在给定延迟后启用的一次性任务。ctx.executor().schedule(() -> {if (ctx.channel().isActive()) {log.info("发送心跳消息给服务端");ctx.writeAndFlush(message);// 递归调用,发送下一次的心跳heartBeat(ctx, message);}}, HEART_BEAT_INTERVAL, TimeUnit.SECONDS);}// 接收到服务器的心跳回写@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (!(msg instanceof MessageProtos.Message message)) {super.channelRead(ctx, msg);return;}if (message.getType() == MessageProtos.HeadType.HEART_BEAT) {log.info("收到会写的心跳信息");} else {super.channelRead(ctx, msg);} }
}
在HeartBeatClientHandler实例被加入到流水线时,它重写的handlerAdded方法被回调。在handlerAdded方法中开始调用heartBeat方法发送心跳数据包。heartBeat是一个不断递归调用的方法,它使用了ctx.executor()获取当前通道绑定的Reactor反应器NIO线,然后通过NIO现线程的schedule定时调度方法,在50s后触发这个方法的执行,再之后递归调用同样延时50s后继续发送。
客户端的心跳间隔要比服务器端的空闲检测时间间隔要短,一般来说要比它的一半要短一些,可以直接定义为空闲检测时间间隔的1/3,以防止公网偶发的秒级抖动。
HeartBeatClientHandler实例并不是一开始就装配到流水线中的,它装配的实际实在登录成功之后。
HeartBeatClientHandler实际上也可以集成IdleStateHandler类在客户端进行空闲检测,这样客户端也可以对服务器进行假死判定,在服务器假死的情况下,客户端可以发起重连。
相关文章:
Netty心跳检测
文章目录 一、网络连接假死现象二、服务器端的空闲检测三、客户端的心跳报文 客户端的心跳检测对于任何长连接的应用来说,都是一个非常基础的功能。要理解心跳的重要性,首先需要从网络连接假死的现象说起。 一、网络连接假死现象 什么是连接假死呢&…...
【leaflet】1. 初见
▒ 目录 ▒ 🛫 导读需求开发环境 1️⃣ 概念概念解释特点 2️⃣ 学习路线图3️⃣ html示例🛬 文章小结📖 参考资料 🛫 导读 需求 要做游戏地图了,看到大量产品都使用的leaflet,所以开始学习这个。 开发环境…...
数据结构与算法(Java版) | 详解十大经典排序算法之一:冒泡排序
前面虽然大家已经知道了多种不同的排序算法,但是我一直都没来得及给大家讲,所以,从这一讲起,我就要开始来给大家详细讲解具体的这些排序算法了。 下面,我们先来看第一个最常见的排序,即冒泡排序。 冒泡排…...
轻量封装WebGPU渲染系统示例<24>- Rendering Pass Graph基本用法(源码)
当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/PassNodeGraphTest.ts 此示例基于此渲染系统实现,当前示例TypeScript源码如下: class PassGraph extends WGRPassNodeGraph {constructor() { super();…...
开设自己的网站系类01购买服务器
开始建设自己的网站吧! 编者买了一个服务器打算自己构建一个网站,用于记录生活。网站大概算是一个个人博客吧。记录创建过程的一些步骤 要开设自己的网站,需要执行以下关键步骤 以下只是初步列出了建立自己的网站的大概步骤,后…...
FTP、NFS、SAMBA系统服务一
一、rsync托管xinetd 1、为什么要进行服务托管 独立服务:独立启动脚本 ssh ftp nfs dns ... 依赖服务: 没有独立的启动脚本 rsync telnet 依赖xinetd服务(独立服务) 2、如何将rsync托管给xinetd服务去管理? 第一步࿱…...
transfomer模型——简介,代码实现,重要模块解读,源码,官方
一、什么是transfomer Transformer是一种基于注意力机制(attention mechanism)的神经网络架构,最初由Vaswani等人在论文《Attention Is All You Need》中提出。它在自然语言处理(NLP)领域取得了巨大成功,特…...
队列(Queue):先进先出(FIFO)的数据结构
队列是一种基本的数据结构,用于在计算机科学和编程中管理数据的存储和访问。队列遵循先进先出(First In, First Out,FIFO)原则,即最早入队的元素首先出队。这种数据结构模拟了物理世界中的队列,如排队等待服…...
吃透 Spring 系列—AOP部分
目录 ◆ AOP 简介 - AOP的概念 - AOP思想的实现方案 - 模拟AOP的基础代码 - AOP相关概念 ◆ 基于xml配置的AOP - xml方式AOP快速入门 - xml方式AOP配置详解 - xml方式AOP原理剖析 ◆ 基于注解配置的AOP - 注解方式AOP基本使用 - 注解方式AOP配置详解 - 注解…...
redis 问题解决 2
1.4 数据存储 1、Redis 的数据过期策略是什么? Redis的数据过期策略包括两种机制:被动删除和主动删除。 被动删除: 当某个键被访问时,如果发现这个键已经过期,Redis会立即删除这个键。这意味着如果一个过期的键从未被访问,它就不会被自动删除。这是一种惰性删除策略。主…...
Spring Boot 校验用户上传的图片文件
图片上传是现代应用中非常常见的一种功能,也是风险比较高的一个地方。恶意用户可能会上传一些病毒、木马。这些东西不仅严重威胁服务器的安全还浪费了带宽,磁盘等资源。所以,在图片上传的接口中,一定要对用户上传的文件进行严格的…...
【springboot配置项动态刷新】与【yaml文件转换为java对象】
文章目录 一,序言二,准备工作1. pom.xml引入组件2. 配置文件示例 三,自定义配置项动态刷新编码实现1. 定义自定义配置项对象2. 添加注解实现启动时自动注入3. 实现yml文件监听以及文件变化处理 四,yaml文件转换为java对象1. 无法使…...
JS移动端触屏事件
在我们PC端中有许多的事件,那我们在移动端有没有事件呢?让我为大家介绍一下移动端常用的事件,触屏事件 触屏事件 touch (也称触摸事件),Android 和IOS 都有 touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一…...
C语言——打印1000年到2000年之间的闰年
闰年: 1、能被4整除不能被100整除 2、能被400整除 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int year;for(year 1000; year < 2000; year){if((year%4 0) && (year%100!0) || (year%400 0)){printf("%d ",ye…...
【Linux】【驱动】设备树下的paltform总线
【Linux】【驱动】设备树下的paltform总线 1. 驱动程序的完整代码2. 使用到的相关函数3 使用到的指令3.2 设备上使用的指令 1. 驱动程序的完整代码 主要是展示了通过总线上挂载的方式来实现相关的数据读取 实质上就是几个of函数的调用。 /** Author: topeet* Description: 设…...
洛谷 NOIP 2023 模拟赛-汪了个汪-题解
简要题意 棋盘上有 n n n 行,第 i i i 行有 i i i 个格子。你要在格子填 1 ∼ n 1\sim n 1∼n,满足: 每行第一个数互不相同所有在行上相邻的两个数所组成的无序对互不相同每行的数互不相同 n ≤ 4000 n\le4000 n≤4000 题解 容易发现…...
洛谷 NOIP 2023 模拟赛 P9836 种树
洛谷 NOIP 2023 模拟赛 P9836 种树 文章目录 洛谷 NOIP 2023 模拟赛 P9836 种树题目大意思路code 题目大意 路边有 n n n 棵树,每棵树的 高度 均为正整数,记作 p 1 , p 2 … p n p_1, p_2 \dots p_n p1,p2…pn。 定义一棵树的 宽度 为它高度的…...
链表经典OJ题(链表回文结构,链表带环,链表的深拷贝)
目录 前言 1.反转一个单链表。 2. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。 3.链表的回文结构。 4.链表带环问题(*****) 4.1是否带环 4.2 入环的节点 5.随机链表的复制(链表的深拷贝) 前言…...
AD教程 (十三)常见CHIP封装的创建
AD教程 (十三)常见CHIP(贴片)封装的创建 PCB封装是电子设计图纸和实物之间的映射体,具有精准数据的要求,在实际设计中需要通过规格书获取创建封装的数据参数。 PCB封装和实物的大小一致。PCB封装是承载实物…...
从0到1实现一个前端监控系统(附源码)
目录 一、从0开始 二、上报数据方法 三、上报时机 四、性能数据收集上报 收集上报FP 收集上报FCP 收集上报LCP 收集上报DOMContentLoaded 收集上报onload数据 收集上报资源加载时间 收集上报接口请求时间 五、错误数据收集上报 收集上报资源加载错误 收集上报js错…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
