溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

26. 后臺(tái)程序如何優(yōu)雅的退出

發(fā)布時(shí)間:2020-08-10 17:31:41 來(lái)源:網(wǎng)絡(luò) 閱讀:2636 作者:rongwei84n 欄目:開(kāi)發(fā)技術(shù)

一. 前言

項(xiàng)目初期我們可以使用kill -9 pid的方法來(lái)殺死后臺(tái)服務(wù)進(jìn)程,然后重新部署。

但是隨著時(shí)間發(fā)展,這種簡(jiǎn)單粗暴的方法會(huì)有一些問(wèn)題:

  1. 如何在退出時(shí)清理一些資源?

  2. 如果某個(gè)請(qǐng)求執(zhí)行操作到一半,直接被退出了,就會(huì)造成臟數(shù)據(jù)。

  3. 如何給客戶(hù)端正確的反饋?


二. Java虛擬機(jī)退出鉤子

虛擬機(jī)允許在退出的時(shí)候執(zhí)行鉤子程序,那么我們可以在這個(gè)方法里面作一些釋放資源的操作,如下:

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屬性

這個(gè)屬性的意思是tomcat留給請(qǐng)求執(zhí)行的時(shí)間,默認(rèn)只有2秒,也就是執(zhí)行./shundown.sh之后,請(qǐng)求處理只有2秒的時(shí)間。如果沒(méi)有及時(shí)返回給客戶(hù)端,那么就會(huì)返回客戶(hù)端503錯(cuò)誤。


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++;
            }
        }
 }


這段代碼它會(huì)把unloadDelay分成20份,然后循環(huán)20次檢查請(qǐng)求是否已經(jīng)結(jié)束。

unloadDelay默認(rèn)是2000ms,也就是2秒鐘.


這樣寫(xiě)的好處是即使配置的unloadDelay時(shí)間很長(zhǎng),但是如果請(qǐng)求很快結(jié)束,那么它也不會(huì)等待配置的unloadDelay時(shí)間,它可以提前退出服務(wù)。


如果請(qǐng)求在unloadDelay時(shí)間內(nèi)處理完請(qǐng)求,那么客戶(hù)端就可以接受到正常的結(jié)果。


四. unloadDelay配置

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

<Context unloadDelay="20000">

    ...
</Context>



五. springboot發(fā)送http請(qǐng)求關(guān)閉服務(wù)

在pom.xml中配置

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


在application.properties中配置

#啟用
shutdownendpoints.shutdown.enabled=true

#禁用密碼驗(yàn)證
endpoints.shutdown.sensitive=false


發(fā)送http關(guān)閉命令

curl -X POST host:port/shutdown

得到的返回消息如下:

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


發(fā)送http消息后,它會(huì)拒絕新的請(qǐng)求,2秒內(nèi)讓已有請(qǐng)求執(zhí)行完畢,清理資源。


六. 權(quán)限

如果沒(méi)有權(quán)限,那么任何人發(fā)送curl -X POST host:port/shundown都可以關(guān)閉服務(wù)。

所以,需要添加權(quán)限

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文件中添加用戶(hù)名和密碼

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


3.發(fā)起的http指令中攜帶用戶(hù)名和密碼

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


4.不過(guò)這樣會(huì)導(dǎo)致正常的請(qǐng)求也需要用戶(hù)名和密碼,所以application.properties還得再加一句:

security.basic.enabled=false


5.IP地址驗(yàn)證

如果想另外加上IP地址驗(yàn)證,那么全部配置如下:

endpoints.shutdown.enabled=true
endpoints.shutdown.sensitive=true
security.basic.enabled=false #不影響正常請(qǐng)求
security.user.name=admin
security.user.password=admin
management.security.role=SUPERUSER
management.port=3081 #管理的端口,需要和server.port不同(正常的請(qǐng)求端口)
management.address=127.0.0.1 #只允許本機(jī)發(fā)送http shutdown命令


發(fā)送的指令如下:

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



向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI