Spring 面试题
服务滚动发布,如何确保进程退出期间,待处理和处理中的请求 服务正确处理请求,不出现业务异常呢?
https://mp.weixin.qq.com/s/wyhuaXNurA8PY4-xwiFORg
进程退出时,有应用线程从Spring GetBean,然而Spring 不允许BeanFactory 销毁期间获取bean,导致请求处理失败、数据不一致的未知结果
JVM 优雅退出机制
- 正常退出
- 异常退出
- 强制退出
正常退出
正常退出时,JVM会执行shutdown hook 钩子程序。钩子提供了java代码响应进程退出的机制,例如Spring等框架通过注册shutdownHook钩子程序,监测到进程要退出的信号,然后关闭Spring上下文。
正常关闭的4种方式
- 所有非守护线程退出
- System.exit(0)
- Ctrl+ C 命令行中退出进程
- kill Pid 通知进程退出。
异常退出
OOM是指一个线程新申请一块内存,JVM发现内存不足,于是触发Full GC,但是FullGC以后依然内存不足,于是该线程触发OOM异常。一般情况下线上进程如果出现OOM,需要及时关闭,否则可能不停触发OOM,导致更多的异常。
OOM只是在一个线程抛出异常,如果异常没有捕获,最多只会关闭这一个线程,不会殃及整个JVM。但是服务既然出现OOM,已经说明服务的内存模型存在问题,可能存在内存泄漏,这种情况下理应退出进程,避免更多的失败 。
一般情况下,我们无法获知服务在哪行代码哪个线程出现 OOM,自然无法有效 catch 异常,执行System.exit 退出进程。好在JVM提供参数 配置,可以在 OOM 发生后执行某个策略
-XX:+HeapDumpOnOutOfMemoryError参数表示当JVM发生OOM时,自动生成DUMP文件。-XX:HeapDumpPath= 目录,也可以指定文件名称,例如:−XX:HeapDumpPath={目录},也可以指定文件名称,例如:- XX:HeapDumpPath=目录,也可以指定文件名称,例如:−XX:HeapDumpPath={目录}/java_heapdump.hprof-XX:OnOutOfMemoryError在程序发生OOM异常时,执行指定命令,该参数接下来会详细介绍,也是JVM优雅退出的关键参数-XX:+ExitOnOutOfMemoryError在程序发生OOM异常时,强制退出-XX:+CrashOnOutOfMemoryError在程序发生OOM异常时,强制退出,并生成Crash日志
可以在OnOutOfMemberError 配置脚本,通过脚本kill进程。可以使用以下参数配置,在OOM发生后,kill进程,如果进程在60s未退出,执行kill-9强制关闭。
-XX:OnOutOfMemoryError="kill -15 %p && sleep 60 && kill -9 %p &"
强制退出
- Kill -9 关闭进程
Runtime.halt()- 机器断电、操作系统关机
- 操作系统强制杀死一个进程
- 进程Crash
JVM 的 ShutdownHook钩子程序
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("shutdown hook started");
}
}));
<span style="color: red;">严禁在钩子程序中调用 System.exit方法</span>
shutdownhook 程序会并发执行,无法指定其执行的顺序。