温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2020-08-10 17:31:41 来源:网络 阅读:2585 作者:rongwei84n 栏目:开发技术

一. 前言

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

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

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

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

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


二. Java虚拟机退出钩子

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

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

/**
     * 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中可以配置,如下:

<Context unloadDelay="20000">

    ...
</Context>



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

在pom.xml中配置

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


在application.properties中配置

#启用
shutdownendpoints.shutdown.enabled=true

#禁用密码验证
endpoints.shutdown.sensitive=false


发送http关闭命令

curl -X POST host:port/shutdown

得到的返回消息如下:

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


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


六. 权限

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

所以,需要添加权限

1.pom.xml中添加申明

<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文件中添加用户名和密码

endpoints.shutdown.sensitive=true
security.user.name=admin
security.user.password=admin
management.security.role=SUPERUSER


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

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


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

security.basic.enabled=false


5.IP地址验证

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

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



向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI