-
不进行优雅停止服务器会出现的情况
请求丢失:在内存队列中转发的数据没有通知完
数据丢失:存于内存缓存中数据未持久化到磁盘
业务中断:处理到一半的业务被强行中断,会造成数据的不一致性。
防止出现资源占用不释放情况,比如防止出现数据处理到一半,又或者是比如在数据库进行了加锁操作,但是服务器在加锁时间段内,服务器进程被杀掉了,那数据库锁就不会得到合理的释放。所以在关闭服务之前,我们需要做一些善后工作,比如保存数据、请求资源、下线服务,然后才退出应用。
-
哪些方面需要做善后工作
Sever(Socket)停止,不再接收新的请求
关闭现有连接通道
关闭线程池
-
用什么方式进行关闭,以及使用什么进行善后工作的调用
在linux下,我们使用kill pid ,关闭进程,然后通过触发java shutdownhook的方式进行。
kill -15 pid,15信号是默认信号,实际上是可写可不写,该信号是给进程一次自己杀死自己的机会
kill -9 pid,从外部强制停止进程
我们一般使用 第一种的命令,kill -15 pid。
实践过程中,发现问题:
kill pid 会触发shutdownhook
pkill -p parentPid 并不会触发shutdownhook。
-
Java ShutdownHook编写
Java语言提供一种ShutdownHook(钩子)机制,当JVM接受到系统的关闭通知之后,调用ShutdownHook内的方法,用以完成清理工作,从而平滑的退出应用。
Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { // 关闭server // 停止线程池 }});在server启动时将该逻辑加入。
(1) 触发调用ShutdownHook场景
- kill -15 pid
- 代码执行结束,JVM正常退出
- 应用代码中调用System.exit() 方法
- 应用中发生OOM错误,导致JVM关闭
- 终端中使用Ctr+c (非后台使用)
(2) 注意点
-
可以多次调用,从而增加多个
-
多个ShutdownHook之间并无任何顺序,Java并不会按照加入顺序执行,反而将会并发执行。
-
ShutdownHook需要尽快执行结束。
不要ShutdownHook执行需要被阻塞代码,或者死锁。
为了避免ShutdownHook线程被长时间阻塞,我们可以引入超时机制
-
线程池的关闭
(1)ExecutorService.shutdown() 非阻塞
启动关闭执行先前提交的任务,但不会接受任何新任务。但该方法不会阻塞等待任务执行完成,而是发出一个停止的信号。
(2)ExecutorService.shutdownNow() 非阻塞
尝试停止所有正在执行的任务,暂停正在等待的任务处理,并返回正在等待执行的任务的列表。此方法不会等待主动执行的任务终止,而是尝试强制停止它们。
(3)ExecutorService.awaitTermination() 等待阻塞
阻塞直到关闭请求后所有任务都已完成执行,或者发生超时,或者当前线程被终端。
我们一般是使用shutdown 和 awaitTermination结合使用,shutdown意味着执行程序服务不在接受传入的任务,awaitTermination是在shutdown请求后调用。
-
重启程序脚本编写
启动时将对应进程id写入到中间文件,这边是最后进程的子进程,以下代码是为了获取最后进程的子进程在停止脚本时,使用kill 与 wait指令进行配合使用。
if [ -f server.pid ]; then ! kill $(cat server.pid); wait ${cat server.pid} fi nohup sh -c "java .....jar" echo $(ps --ppid $! -o pid,cmd |grep java|awk '{print $1}') > server.pidwait pid 命令讲解
wait 是linux是内置命令,它等待完成任何正在运行的进程。wait命令与特定的进程ID或作业ID一起使用。阻塞等待pid 进程运行完成。 详解wait命令链接:linuxhint.com/wait_comman…
7.更正第6条
经过实践,wait 命令这样使用不起作用,会报如下错:
wait: pid 856 is not a child of this shell
我猜想它大概是不能等待非shell运行时产生的process。没有时间去探究了,然后换了一种方式去做了。
将阻塞等待kill pid 执行完毕再往下走的命令修改成如下:
while ps -p $(cat server.pid) > /dev/null; do sleep 1; done;
这段命令的意思是一直循环检查该process是否还在。具体详解链接如下: blog.joncairns.com/2013/03/wai…