您好,登錄后才能下訂單哦!
一. 前言
項目初期我們可以使用kill -9 pid的方法來殺死后臺服務進程,然后重新部署。
但是隨著時間發展,這種簡單粗暴的方法會有一些問題:
如何在退出時清理一些資源?
如果某個請求執行操作到一半,直接被退出了,就會造成臟數據。
如何給客戶端正確的反饋?
二. 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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。