打印测试页显示由于线程退出_Netty 优雅退出机制和原理

本文详细介绍了Netty的优雅退出机制,包括进程优雅退出的重要性,如何在Java中实现优雅退出,以及Netty优雅退出的步骤和原理。通过设置信号、注册ShutdownHook和调用EventLoopGroup的shutdownGracefully方法,确保线程安全地停止,同时处理完剩余任务。文章还澄清了一些关于Netty优雅退出的常见误区,并深入解析了NioEventLoopGroup、NioEventLoop、AbstractUnsafe和TaskQueue等关键组件在退出过程中的作用。最后讨论了在退出过程中可能遇到的消息丢失问题及其原因。
摘要由CSDN通过智能技术生成
4facb2e6ea302719b894a58ea9134dac.gif

点击上方蓝色字体,关注我们

92f8d942eca5c6db95e8b3a8e8481543.gif

1. 进程的优雅退出

1.1.Kill -9 PID 带来的问题

在 Linux 上通常会通过 kill -9 pid 的方式强制将某个进程杀掉,这种方式简单高效,因此很多程序的停止脚本经常会选择使用 kill -9 pid 的方式。

无论是 Linux 的 Kill -9 pid 还是 windows 的 taskkill /f /pid 强制进程退出, 都会带来一些副作用:对应用软件而言其效果等同于突然掉电,可能会导致如下一些问题:

  1. 缓存中的数据尚未持久化到磁盘中,导致数据丢失;

  2. 正在进行文件的 write 操作,没有更新完成,突然退出,导致文件损坏;

  3. 线程的消息队列中尚有接收到的请求消息还没来得及处理,导致请求消息丢失;

  4. 数据库操作已经完成,例如账户余额更新,准备返回应答消息给客户端时,消息尚在通信线程的发送队列中排队等待发送,进程强制退出导致应答消息没有返回给客户端,客户端发起超时重试,会带来重复更新问题;

  5. 其它问题等...

1.2.JAVA 优雅退出

Java 的优雅停机通常通过注册 JDK 的 ShutdownHook 来实现,当系统接收到退出指令后,首先标记系统处于退出状态,不再接收新的消息,然后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各线程退出执行。

通常优雅退出需要有超时控制机制,例如 30S,如果到达超时时间仍然没有完成退出前的资源回收等操作,则由停机脚本直接调用 kill -9 pid,强制退出。

2. 如何实现 Netty 的优雅退出

要实现 Netty 的优雅退出,首先需要了解通用 Java 进程的优雅退出如何实现。下面我们先讲解下优雅退出的实现原理,并结合实际代码进行讲解。最后看下如何实现 Netty 的优雅退出。

2.0.1. 信号简介

信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的,它是进程间一种异步通信的机制。以 Linux 的 kill 命令为例,kill -s SIGKILL pid (即 kill -9 pid) 立即杀死指定 pid 的进程,SIGKILL 就是发送给 pid 进程的信号。

信号具有平台相关性,Linux 平台支持的一些终止进程信号如下所示:

信号名称

用途

SIGKILL

终止进程,强制杀死进程

SIGTERM

终止进程,软件终止信号

SIGTSTP

停止进程,终端来的停止信号

SIGPROF

终止进程,统计分布图用计时器到时

SIGUSR1

终止进程,用户定义信号 1

SIGUSR2

终止进程,用户定义信号 2

SIGINT

终止进程,中断进程

SIGQUIT

建立 CORE 文件终止进程,并且生成 core 文件

Windows 平台存在一些差异,它的一些信号举例如下:SIGINT(Ctrl+C 中断)、SIGILL、SIGTERM (kill 发出的软件终止)、SIGBREAK (Ctrl+Break 中断)。

信号选择:为了不干扰正常信号的运作,又能模拟 Java 异步通知,在 Linux 上我们需要先选定一种特殊的信号。通过查看信号列表上的描述,发现 SIGUSR1 和 SIGUSR2 是允许用户自定义的信号, 我们可以选择 SIGUSR2,为了测试方便,在 Windows 上我们可以选择 SIGINT。

2.0.2. Java 程序的优雅退出

首先看下通用的 Java 进程优雅退出的流程图:

365bb82e2b6bbc984e8a57df6ed0558b.png

第一步,应用进程启动的时候,初始化 Signal 实例,它的代码示例如下:

Signal sig = new Signal(getOSSignalType());

其中 Signal 构造函数的参数为 String 字符串,也就是 2.1.1 小节中介绍的信号量名称。

第二步,根据操作系统的名称来获取对应的信号名称,代码如下:

private String getOSSignalType()   {
           return System.getProperties().getProperty("os.name").     toLowerCase().startsWith("win") ? "INT" : "USR2";    }

判断是否是 windows 操作系统,如果是则选择 SIGINT,接收 Ctrl+C 中断的指令;否则选择 USR2 信号,接收 SIGUSR2(等价于 kill -12 pid)指令。

第三步,将实例化之后的 Si

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值