26. 后台程序如何优雅的退出

简介:

一. 前言

项目初期我们可以使用kill -9 pid的方法来杀死后台服务进程,然后重新部署。

但是随着时间发展,这种简单粗暴的方法会有一些问题:

  1. 如何在退出时清理一些资源?

  2. 如果某个请求执行操作到一半,直接被退出了,就会造成脏数据。

  3. 如何给客户端正确的反馈?


二. Java虚拟机退出钩子

虚拟机允许在退出的时候执行钩子程序,那么我们可以在这个方法里面作一些释放资源的操作,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
System.out.println( "add hook..." );
Thread shutdownThread =  new  Thread( new  Runnable() {
     @Override
     public  void  run() {
     System.out.println( "hook running.."  + System.currentTimeMillis());
                 
         try  {
         Thread.sleep( 10000 );
         catch  (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
         }
                 
         System.out.println( "hook sleep done..."  + System.currentTimeMillis());
     }
});
         
Runtime.getRuntime().addShutdownHook(shutdownThread);



三. tomcat的unloadDelay属性

这个属性的意思是tomcat留给请求执行的时间,默认只有2秒,也就是执行./shundown.sh之后,请求处理只有2秒的时间。如果没有及时返回给客户端,那么就会返回客户端503错误。


apache-tomcat-9.0.0.M22-src/java/org/apache/catalina/core/StandardWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
      * Wait time for servlet unload in ms.
      */
protected  long  unloadDelay =  2000 ;
 
public  synchronized  void  unload()  throws  ServletException {
         
         // Nothing to do if we have never loaded the instance
         if  (!singleThreadModel && (instance ==  null )) {
              log.info( "instance run..." );
              return ;
         }
            
         unloading =  true ;
 
         log.info( "countAllocated.get(): "  + countAllocated.get());
         // Loaf a while if the current instance is allocated
         // (possibly more than once if non-STM)
         if  (countAllocated.get() >  0 ) {
             int  nRetries =  0 ;
             long  delay = unloadDelay /  20 ;
             System.out.println( "unloadDelay: "  + unloadDelay);
             log.info( "unloadDelay 2222: "  + unloadDelay);
             while  ((nRetries <  21 ) && (countAllocated.get() >  0 )) {
                 if  ((nRetries %  10 ) ==  0 ) {
                     log.info(sm.getString( "standardWrapper.waiting" ,
                                           countAllocated.toString(),
                                           getName()));
                 }
                 try  {
                     Thread.sleep(delay);
                 catch  (InterruptedException e) {
                     // Ignore
                 }
                 nRetries++;
             }
         }
  }


这段代码它会把unloadDelay分成20份,然后循环20次检查请求是否已经结束。

unloadDelay默认是2000ms,也就是2秒钟.


这样写的好处是即使配置的unloadDelay时间很长,但是如果请求很快结束,那么它也不会等待配置的unloadDelay时间,它可以提前退出服务。


如果请求在unloadDelay时间内处理完请求,那么客户端就可以接受到正常的结果。


四. unloadDelay配置

在tomcat的conf目录下的context.xml中可以配置,如下:

1
2
3
4
< Context  unloadDelay = "20000" >
 
     ...
</ Context >



五. springboot发送http请求关闭服务

在pom.xml中配置

1
2
3
< dependency >
   < groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-actuator</ artifactId ></ dependency >


在application.properties中配置

1
2
3
4
5
#启用
shutdownendpoints.shutdown.enabled=true
 
#禁用密码验证
endpoints.shutdown.sensitive=false


发送http关闭命令

1
curl -X POST host:port/shutdown

得到的返回消息如下:

1
{"message":"Shutting down, bye..."}


发送http消息后,它会拒绝新的请求,2秒内让已有请求执行完毕,清理资源。


六. 权限

如果没有权限,那么任何人发送curl -X POST host:port/shundown都可以关闭服务。

所以,需要添加权限

1.pom.xml中添加申明

1
2
3
4
5
6
7
8
9
< dependency >
    < groupId >org.springframework.boot</ groupId >
    < artifactId >spring-boot-starter-security</ artifactId >
</ dependency >
 
< dependency >
     < groupId >org.springframework.boot</ groupId >
     < artifactId >spring-boot-starter-actuator</ artifactId >
</ dependency >

spring-boot-starter-actuator的作用参考这篇帖子:

Springboot startr作用详解



2.appliaction.properties文件中添加用户名和密码

1
2
3
4
endpoints.shutdown.sensitive=true
security.user.name=admin
security.user.password=admin
management.security.role=SUPERUSER


3.发起的http指令中携带用户名和密码

1
curl -uadmin:admin -X POST http://host:port/shutdown


4.不过这样会导致正常的请求也需要用户名和密码,所以application.properties还得再加一句:

1
security.basic.enabled=false


5.IP地址验证

如果想另外加上IP地址验证,那么全部配置如下:

1
2
3
4
5
6
7
8
endpoints.shutdown.enabled=true
endpoints.shutdown.sensitive=true
security.basic.enabled=false #不影响正常请求
security.user.name=admin
security.user.password=admin
management.security.role=SUPERUSER
management.port=3081 #管理的端口,需要和server.port不同(正常的请求端口)
management.address=127.0.0.1 #只允许本机发送http shutdown命令


发送的指令如下:

curl -uadmin:admin -X POST http://localhost:3081/shutdown




     本文转自rongwei84n 51CTO博客,原文链接: http://blog.51cto.com/483181/1943154 ,如需转载请自行联系原作者

相关文章
|
5月前
|
Cloud Native Linux Go
原来服务端的退出姿势也可以这么优雅
原来服务端的退出姿势也可以这么优雅
|
23天前
|
Shell Linux
Linux脚本Shell脚本来实现一次性kill多个端口的进程
Linux脚本Shell脚本来实现一次性kill多个端口的进程
5 0
|
10月前
|
Unix Linux Shell
查看后台运行的命令 、进程状态、关闭前后台命令
查看后台运行的命令 、进程状态、关闭前后台命令
|
Shell
shell脚本控制程序启动停止重启
shell脚本控制程序启动停止重启
238 0
|
Windows
Win10 关机显示程序没有响应
具体表现,每次关机都提示某一个程序没有响应,在进程,服务中都找不到对应的的程序。
393 0
Win10 关机显示程序没有响应
|
Windows
Windows 技术篇-任务管理器查看执行进程的程序所在位置方法,查看执行进程的命令行
Windows 技术篇-任务管理器查看执行进程的程序所在位置方法,查看执行进程的命令行
246 0
Windows 技术篇-任务管理器查看执行进程的程序所在位置方法,查看执行进程的命令行
|
Linux
Linux命令行下:把程序放后台执行,以及从后台继续执行程序
把任务放到后台用 & 和 Ctrl+z 让后台任务从停止状态转为运行状态用 bg %N 把后台任务调回到前台用 fg %N 查看所有任务用jobs
2112 0

热门文章

最新文章