SpringBoot3實(shí)現(xiàn)優(yōu)雅停機(jī)的完整流程
在現(xiàn)代微服務(wù)架構(gòu)中,優(yōu)雅停機(jī)(Graceful Shutdown)是一項(xiàng)重要功能,可以確保服務(wù)在關(guān)閉時處理完所有當(dāng)前請求,避免突然終止連接或丟失數(shù)據(jù)。Spring Boot 3 提供了對優(yōu)雅停機(jī)的內(nèi)置支持,允許在關(guān)閉應(yīng)用程序上下文期間為現(xiàn)有請求設(shè)置一個寬限期,同時防止新請求進(jìn)入。本文將詳細(xì)介紹 Spring Boot 3 的優(yōu)雅停機(jī)機(jī)制,重點(diǎn)分析 Tomcat 和 Reactor Netty 兩種常用的嵌入式 Web 服務(wù)器的優(yōu)雅停機(jī)流程。
1. 什么是優(yōu)雅停機(jī)?
優(yōu)雅停機(jī)的目標(biāo)是在服務(wù)關(guān)閉時:
- 允許當(dāng)前的處理請求在指定的寬限期內(nèi)完成。
- 阻止新的請求進(jìn)入。
- 向外部監(jiān)控或負(fù)載均衡器標(biāo)記服務(wù)為不可用。
這種機(jī)制可以確保服務(wù)在維護(hù)或版本升級時避免數(shù)據(jù)丟失和請求中斷,提供更高的穩(wěn)定性和可用性。
2. Spring Boot 3 優(yōu)雅停機(jī)的配置
在 Spring Boot 3 中,我們可以使用 server.shutdown
配置來開啟優(yōu)雅停機(jī),并指定寬限期。配置項(xiàng)如下:
server: shutdown: "graceful" # 開啟優(yōu)雅停機(jī) spring: lifecycle: timeout-per-shutdown-phase: "20s" # 停機(jī)的寬限期,默認(rèn)為 30 秒
此配置項(xiàng)適用于所有四種嵌入式 Web 服務(wù)器:Tomcat、Jetty、Reactor Netty 和 Undertow。
注意:Spring Boot 3 默認(rèn)禁用優(yōu)雅停機(jī),需要將
server.shutdown
設(shè)置為graceful
以啟用。
3. Tomcat 和 Reactor Netty 的優(yōu)雅停機(jī)機(jī)制
Spring Boot 3 支持在不同的 Web 服務(wù)器上實(shí)現(xiàn)優(yōu)雅停機(jī)。以下是 Tomcat 和 Reactor Netty 的具體停機(jī)方式:
3.1 Tomcat 優(yōu)雅停機(jī)
使用Tomcat的優(yōu)雅關(guān)機(jī)需要Tomcat 9.0.33或更高版本,在 Tomcat 上啟用優(yōu)雅停機(jī)后,當(dāng)收到關(guān)閉信號時,它將停止接受新的連接請求,并在網(wǎng)絡(luò)層阻止傳入流量:
- 阻止新請求:一旦啟動關(guān)閉流程,Tomcat 將在網(wǎng)絡(luò)層拒絕新的請求連接。
- 完成現(xiàn)有請求:Tomcat 會確保已有請求在指定的寬限期內(nèi)完成。如果請求未完成且寬限期到達(dá),將強(qiáng)制終止。
注意:若某些請求未在寬限期內(nèi)完成,則這些請求將被中斷。
3.2 Reactor Netty 優(yōu)雅停機(jī)
Reactor Netty 是 Spring WebFlux 默認(rèn)使用的非阻塞式 Web 服務(wù)器,適合響應(yīng)式編程。Reactor Netty 的優(yōu)雅停機(jī)實(shí)現(xiàn)方式如下:
- 網(wǎng)絡(luò)層停止:當(dāng)關(guān)閉信號到達(dá),Reactor Netty 將停止接受新請求連接,并釋放相關(guān)資源。
- 等待寬限期:當(dāng)前所有活動請求在寬限期內(nèi)繼續(xù)處理;在寬限期結(jié)束后,未完成的請求將被強(qiáng)制中止。
Reactor Netty 在優(yōu)雅停機(jī)期間通過停止接受新的連接來實(shí)現(xiàn)無縫停機(jī)。其無阻塞模型讓服務(wù)在短時間內(nèi)完成停機(jī)。
Reactor Netty 在優(yōu)雅停機(jī)期間通過停止接受新的連接來實(shí)現(xiàn)無縫停機(jī)。其無阻塞模型讓服務(wù)在短時間內(nèi)完成停機(jī)。
4. 優(yōu)雅停機(jī)的流程
在 Tomcat 和 Reactor Netty 上的優(yōu)雅停機(jī)流程類似,大致包含以下幾個步驟:
- 標(biāo)記服務(wù)不可用:停止接收新的請求,通常是通過在負(fù)載均衡器中剔除該服務(wù)或在網(wǎng)絡(luò)層阻斷連接來實(shí)現(xiàn)。
- 設(shè)置寬限期:當(dāng)前請求允許在寬限期內(nèi)繼續(xù)處理。
- 關(guān)閉活動連接:寬限期結(jié)束后,所有未完成的請求會被中止,資源釋放。
Spring Boot 3 的 SmartLifecycle
和 ApplicationContext
控制器在關(guān)閉階段對生命周期進(jìn)行管理,保證所有組件按照順序優(yōu)雅停止。
5. 實(shí)現(xiàn)優(yōu)雅停機(jī)的完整示例
我們可以創(chuàng)建一個簡單的 Spring Boot 3 應(yīng)用來展示優(yōu)雅停機(jī)配置。
5.1 代碼示例
在 application.yml
中啟用優(yōu)雅停機(jī)并設(shè)置寬限期為 30 秒:
server: shutdown: "graceful" # 開啟優(yōu)雅停機(jī) spring: lifecycle: timeout-per-shutdown-phase: "30s" # 停機(jī)的寬限期,默認(rèn)為 30 秒
創(chuàng)建一個簡單的 REST 控制器,模擬一個處理時間較長的請求:
@RestController @RequestMapping("/api") public class DemoController { @GetMapping("/long-running") public String longRunningTask() throws InterruptedException { System.out.println("開始執(zhí)行耗時任務(wù)..."); Thread.sleep(20000); // 模擬耗時任務(wù) return "任務(wù)完成"; } }
此控制器會等待 20 秒后返回結(jié)果。通過優(yōu)雅停機(jī)機(jī)制,即使應(yīng)用關(guān)閉,也會允許該任務(wù)在 30 秒寬限期內(nèi)完成。
啟動類里添加一段代碼方便打印服務(wù)何時停止運(yùn)行:
@PreDestroy public void destroy() { System.out.println("Application is destroyed"); }
5.2 IDEA 停止服務(wù)
由于 IDEA 運(yùn)行的服務(wù)點(diǎn)擊紅點(diǎn)結(jié)束,會直接停止程序,無法模擬停機(jī),Linux 上通過 java -jar 運(yùn)行的程序沒有這種煩惱,所有此處引入 actuator 的功能,它可以執(zhí)行 shutdown。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
增加如下 actuator 配置:
management: endpoints: web: exposure: include: '*' endpoint: shutdown: enabled: true # 開放停機(jī)端口
調(diào)用 curl -X POST http://localhost:8080/actuator/shutdown
,即可停止服務(wù):
5.3 測試優(yōu)雅停機(jī)
啟動應(yīng)用并訪問 http://localhost:8080/api/long-running
,然后調(diào)用 http://localhost:8080/actuator/shutdown
停止服務(wù)。
請求在寬限期內(nèi)返回 任務(wù)完成
。
修改超期時間為 10s,超過寬限期后,請求被中止。
6. 負(fù)載均衡器中的停機(jī)策略
在實(shí)際應(yīng)用中,負(fù)載均衡器(如 Nginx、Kubernetes)也可以在服務(wù)停機(jī)時配合優(yōu)雅停機(jī)流程,通過從負(fù)載均衡池中剔除當(dāng)前實(shí)例來防止新流量進(jìn)入。這樣可以確保所有請求被其他實(shí)例接管,而當(dāng)前實(shí)例只處理已有請求,直至完成后停機(jī)。
7. 優(yōu)雅停機(jī)的注意事項(xiàng)
- 寬限期配置:設(shè)置合理的寬限期,確保長時間請求可以完成。
- 負(fù)載均衡器協(xié)作:在生產(chǎn)環(huán)境中建議與負(fù)載均衡器配合,實(shí)現(xiàn)完整的優(yōu)雅停機(jī)流程。
- 避免頻繁停機(jī):頻繁停機(jī)會中斷長時間任務(wù),應(yīng)避免在高負(fù)載時頻繁重啟應(yīng)用。
8. 總結(jié)
在 Spring Boot 3 中,通過簡單配置即可實(shí)現(xiàn)優(yōu)雅停機(jī),確保服務(wù)在關(guān)閉時能夠完整處理當(dāng)前請求,減少對用戶體驗(yàn)的影響。在 Tomcat 和 Reactor Netty 上實(shí)現(xiàn)的優(yōu)雅停機(jī)過程相似,都采用了在網(wǎng)絡(luò)層阻止新請求和在應(yīng)用層設(shè)置寬限期的方式。優(yōu)雅停機(jī)機(jī)制在高并發(fā)服務(wù)中顯得尤為重要,是微服務(wù)架構(gòu)中保持穩(wěn)定性和一致性的關(guān)鍵。
以上就是SpringBoot3實(shí)現(xiàn)優(yōu)雅停機(jī)的完整流程的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot3優(yōu)雅停機(jī)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java通過cglib動態(tài)生成實(shí)體bean的操作
這篇文章主要介紹了java通過cglib動態(tài)生成實(shí)體bean的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之隊(duì)列
這篇文章主要介紹了Java隊(duì)列數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),隊(duì)列是一種特殊的線性表,只允許在表的隊(duì)頭進(jìn)行刪除操作,在表的后端進(jìn)行插入操作,隊(duì)列是一個有序表先進(jìn)先出,想了解更多相關(guān)資料的小伙伴可以參考下面文章的詳細(xì)內(nèi)容2022-02-02Java創(chuàng)建多線程異步執(zhí)行實(shí)現(xiàn)代碼解析
這篇文章主要介紹了Java創(chuàng)建多線程異步執(zhí)行實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07解析springboot集成AOP實(shí)現(xiàn)日志輸出的方法
如果這需要在每一個controller層去寫的話代碼過于重復(fù),于是就使用AOP定義切面 對其接口調(diào)用前后進(jìn)行攔截日志輸出。接下來通過本文給大家介紹springboot集成AOP實(shí)現(xiàn)日志輸出,需要的朋友可以參考下2021-11-11深入學(xué)習(xí)Java編程中的字符串的進(jìn)階使用
這篇文章主要介紹了Java編程中的字符串的高級運(yùn)用,包括StringBuffer類和StringTokenizer類以及常量池的介紹,需要的朋友可以參考下2016-01-01SpringBoot配置文件properties和yml的實(shí)現(xiàn)
本文主要介紹了SpringBoot配置文件properties和yml的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04如何解決java:找不到符號符號:類__(使用了lombok的注解)
在使用IntelliJ IDEA開發(fā)Java項(xiàng)目時,可能遇到通過@lombok注解自動生成get和set方法不生效的問題,解決這一問題需要幾個步驟,首先,確認(rèn)Lombok插件已在IDEA中安裝并啟用,其次,確保項(xiàng)目中已添加Lombok的依賴,對于Maven和Gradle項(xiàng)目2024-10-10