SpringBoot實現(xiàn)應(yīng)用開機自啟動與進程守護配置方案
一個故(shi)事(gu)
"小王,生產(chǎn)環(huán)境怎么回事?服務(wù)全掛了!"
上個月一個周六的凌晨,小王被這通電話驚醒。
機房意外斷電,恢復(fù)供電后所有服務(wù)器重啟,但我們的SpringBoot應(yīng)用沒有自動啟動,導(dǎo)致業(yè)務(wù)中斷了整整40分鐘。
事后排查發(fā)現(xiàn),是之前的運維同事離職時沒有留下開機自啟動配置文檔。更糟的是,應(yīng)用運行中偶爾會因為OOM崩潰,也沒有任何進程守護機制。
經(jīng)歷這次事故后,小王整理了兩套SpringBoot應(yīng)用開機自啟動與進程守護方案,在生產(chǎn)環(huán)境穩(wěn)定運行至今。
方案一:systemd配置(推薦)
什么是systemd?
簡單說,systemd是現(xiàn)在Linux系統(tǒng)的"大管家",負責管理系統(tǒng)啟動和服務(wù)進程。
幾乎所有主流Linux(CentOS 、Ubuntu 、Debian等)都支持使用systemd。
為什么推薦它?因為:
原生集成:不需要額外安裝軟件 功能強大:支持開機自啟、進程監(jiān)控、日志管理 配置簡單:一個服務(wù)文件搞定所有設(shè)置
實戰(zhàn)步驟:從0到1配置
1. 準備SpringBoot應(yīng)用
假設(shè)我們的應(yīng)用信息:
- 應(yīng)用名稱:demo-app
- JAR文件路徑:
/opt/apps/demo-app.jar - 運行用戶:appuser(建議使用非root用戶)
- 日志路徑:
/var/log/demo-app.log
2. 創(chuàng)建啟動腳本(關(guān)鍵)
不要直接在systemd中調(diào)用java命令!創(chuàng)建一個啟動腳本/opt/apps/start.sh:
#!/bin/bash
# SpringBoot應(yīng)用啟動腳本
APP_NAME="demo-app"
JAR_FILE="/opt/apps/demo-app.jar"
LOG_FILE="/var/log/${APP_NAME}.log"
JVM_OPTS="-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
SERVER_PORT=8080
# 檢查JAR文件是否存在
if [ ! -f "$JAR_FILE" ]; then
echo "錯誤:JAR文件 $JAR_FILE 不存在!"
exit 1
fi
# 檢查端口是否被占用
check_port() {
netstat -tlnp | grep ":$SERVER_PORT " > /dev/null
return $?
}
if check_port; then
echo "錯誤:端口 $SERVER_PORT 已被占用!"
netstat -tlnp | grep ":$SERVER_PORT "
exit 1
fi
# 啟動應(yīng)用
echo "開始啟動 $APP_NAME ..."
nohup java $JVM_OPTS -jar $JAR_FILE --server.port=$SERVER_PORT > $LOG_FILE 2>&1 &
# 等待應(yīng)用啟動
echo "等待應(yīng)用啟動,端口:$SERVER_PORT ..."
for i in {1..30}; do
if check_port; then
echo "$APP_NAME 啟動成功!"
echo "日志文件:$LOG_FILE"
exit 0
fi
sleep 1
done
# 啟動超時處理
echo "錯誤:$APP_NAME 啟動超時!"
echo "查看日志獲取詳細信息:tail -f $LOG_FILE"
exit 1
給腳本添加執(zhí)行權(quán)限:
chmod +x /opt/apps/start.sh
3. 創(chuàng)建systemd服務(wù)文件
創(chuàng)建/etc/systemd/system/demo-app.service:
[Unit] Description=Demo SpringBoot Application Documentation=https://example.com/docs After=network.target mysql.service # 依賴網(wǎng)絡(luò)和MySQL服務(wù)啟動后再啟動 Wants=mysql.service # MySQL啟動失敗不影響本服務(wù)啟動 [Service] User=appuser Group=appuser WorkingDirectory=/opt/apps ExecStart=/opt/apps/start.sh # 自定義停止命令(優(yōu)雅關(guān)閉) ExecStop=/bin/bash -c "PID=$(pgrep -f 'demo-app.jar'); if [ -n "$PID" ]; then kill -15 $PID; sleep 10; if ps -p $PID > /dev/null; then kill -9 $PID; fi; fi" # 啟動前備份日志 ExecStartPre=/bin/bash -c "if [ -f /var/log/demo-app.log ]; then mv /var/log/demo-app.log /var/log/demo-app.log.$(date +%%Y%%m%%d%%H%%M%%S); fi" SuccessExitStatus=143 # 識別SpringBoot優(yōu)雅關(guān)閉狀態(tài)碼 Restart=always # 總是重啟(異常退出時) RestartSec=5 # 重啟間隔5秒 TimeoutStartSec=300 # 啟動超時時間(5分鐘) TimeoutStopSec=60 # 停止超時時間 Environment="SPRING_PROFILES_ACTIVE=prod" # 環(huán)境變量 Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk" [Install] WantedBy=multi-user.target # 多用戶模式下啟動
4. 服務(wù)管理命令
# 重載systemd配置(修改服務(wù)文件后必須執(zhí)行) sudo systemctl daemon-reload # 啟動服務(wù) sudo systemctl start demo-app # 停止服務(wù) sudo systemctl stop demo-app # 重啟服務(wù) sudo systemctl restart demo-app # 設(shè)置開機自啟 sudo systemctl enable demo-app # 取消開機自啟 sudo systemctl disable demo-app # 查看服務(wù)狀態(tài) sudo systemctl status demo-app # 查看服務(wù)日志 sudo journalctl -u demo-app -f # -f表示實時跟蹤
狀態(tài)檢查示例:
demo-app.service - Demo SpringBoot Application
Loaded: loaded (/etc/systemd/system/demo-app.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2023-11-15 10:30:00 CST; 5min ago
Docs: https://example.com/docs
Process: 1234 ExecStartPre=/bin/bash -c if [ -f /var/log/demo-app.log ]; then mv /var/log/demo-app.log /var/log/demo-app.log.20231115102959; fi (code=exited, status=0/SUCCESS)
Main PID: 1245 (start.sh)
Tasks: 30 (limit: 4915)
Memory: 256.0M
CGroup: /system.slice/demo-app.service
├─1245 /bin/bash /opt/apps/start.sh
└─1250 java -Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar /opt/apps/demo-app.jar --server.port=8080
避坑指南
坑1:權(quán)限問題導(dǎo)致啟動失敗
現(xiàn)象:Job for demo-app.service failed because the control process exited with error code.
解決:確保appuser用戶有JAR文件和日志目錄的權(quán)限
sudo chown -R appuser:appuser /opt/apps /var/log/demo-app.log
坑2:應(yīng)用啟動慢導(dǎo)致超時
現(xiàn)象:Failed to start Demo SpringBoot Application. Timeout was reached.
解決:增加啟動超時時間
[Service] TimeoutStartSec=300 # 5分鐘
坑3:優(yōu)雅關(guān)閉不生效
現(xiàn)象:執(zhí)行stop后應(yīng)用立即退出,@PreDestroy方法未執(zhí)行
解決:配置優(yōu)雅關(guān)閉參數(shù)
[Service] KillSignal=SIGTERM TimeoutStopSec=60
同時在SpringBoot配置文件中添加:
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
方案二:Supervisor配置(兼容更多系統(tǒng))
如果你的服務(wù)器是較老的Linux發(fā)行版(如CentOS 6),或者需要管理多個進程,Supervisor是個不錯的選擇。
它是Python編寫的進程管理工具,跨平臺性好。
安裝Supervisor
CentOS安裝:
# 安裝EPEL源 sudo yum install -y epel-release # 安裝Supervisor sudo yum install -y supervisor # 啟動并設(shè)置開機自啟 sudo systemctl start supervisord sudo systemctl enable supervisord
Ubuntu安裝:
sudo apt-get update sudo apt-get install -y supervisor
創(chuàng)建應(yīng)用配置文件
創(chuàng)建/etc/supervisord.d/demo-app.ini:
[program:demo-app]
command=/usr/bin/java -Xms512m -Xmx512m -XX:+UseG1GC -jar /opt/apps/demo-app.jar --server.port=8080
directory=/opt/apps
user=appuser
autostart=true # 隨Supervisor啟動而啟動
autorestart=true # 進程退出時自動重啟
startretries=3 # 啟動失敗重試次數(shù)
startsecs=10 # 啟動后穩(wěn)定運行10秒才算成功
redirect_stderr=true # 錯誤日志重定向到標準輸出
stdout_logfile=/var/log/demo-app.log
stdout_logfile_maxbytes=10MB # 日志文件大小限制
stdout_logfile_backups=10 # 日志備份數(shù)量
environment=
SPRING_PROFILES_ACTIVE="prod",
JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
Supervisor管理命令
# 重載配置(修改配置后執(zhí)行) sudo supervisorctl update # 查看所有進程狀態(tài) sudo supervisorctl status # 啟動應(yīng)用 sudo supervisorctl start demo-app # 停止應(yīng)用 sudo supervisorctl stop demo-app # 重啟應(yīng)用 sudo supervisorctl restart demo-app # 查看應(yīng)用日志 sudo supervisorctl tail -f demo-app
實戰(zhàn)經(jīng)驗: "Supervisor的日志輪轉(zhuǎn)功能非常實用,但要注意單位是MB不是GB!另外,它本身也需要通過systemd來管理開機啟動,有點套娃的感覺。"
兩種方案對比與選擇建議
| 特性 | systemd | Supervisor |
|---|---|---|
| 系統(tǒng)集成 | 原生集成,無需額外安裝 | 需要單獨安裝 |
| 配置復(fù)雜度 | 中等 | 簡單 |
| 進程監(jiān)控 | 支持 | 支持 |
| 多應(yīng)用管理 | 配置文件分散 | 集中管理 |
| 跨平臺性 | 僅Linux | Linux/Unix/Mac |
使用建議
生產(chǎn)環(huán)境首選systemd:原生、輕量、功能足夠 多應(yīng)用管理選Supervisor:集中配置,適合管理多個微服務(wù) Docker環(huán)境不需要:容器本身提供進程管理
高級配置:健康檢查與自動恢復(fù)
systemd健康檢查
創(chuàng)建健康檢查腳本/opt/apps/healthcheck.sh:
#!/bin/bash
PORT=8080
TIMEOUT=5
# 檢查健康端點
result=$(curl -s -w "%{http_code}" -o /dev/null --connect-timeout $TIMEOUT http://localhost:$PORT/actuator/health)
if [ "$result" -eq 200 ]; then
exit 0
else
echo "健康檢查失敗,HTTP狀態(tài)碼: $result"
exit 1
fi
修改服務(wù)文件添加健康檢查
[Service] HealthCheckSec=30 # 每30秒檢查一次 HealthCheckCmd=/opt/apps/healthcheck.sh HealthCheckFailureAction=restart # 檢查失敗則重啟
SpringBoot需暴露健康端點
management:
endpoints:
web:
exposure:
include: health
endpoint:
health:
show-details: always
probes:
enabled: true
"健康檢查是防止'僵尸進程'的有效手段。我們可能會遇到應(yīng)用進程存在但無法提供服務(wù)的情況,有了健康檢查后,systemd會自動重啟這類異常應(yīng)用。"
防止無限重啟策略
無論是systemd還是Supervisor,都需要配置重啟限制,避免應(yīng)用陷入重啟循環(huán):
systemd配置:
[Unit] StartLimitInterval=600 # 10分鐘內(nèi) StartLimitBurst=5 # 最多重啟5次 StartLimitAction=poweroff # 達到限制后關(guān)閉系統(tǒng)(極端情況)
Supervisor配置:
[program:demo-app] autorestart=unexpected # 僅意外退出時重啟 exitcodes=0,143 # 正常退出狀態(tài)碼
總結(jié)
按照這些步驟配置后,你的SpringBoot應(yīng)用將具備服務(wù)器重啟或應(yīng)用異常down掉后自動恢復(fù)的能力。
以上就是SpringBoot實現(xiàn)應(yīng)用開機自啟動與進程守護配置方案的詳細內(nèi)容,更多關(guān)于SpringBoot應(yīng)用開機自啟動與進程守護的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringMVC后端返回數(shù)據(jù)到前端代碼示例
這篇文章主要介紹了SpringMVC后端返回數(shù)據(jù)到前端代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-04-04
創(chuàng)建一個IDEA的Java項目實現(xiàn)方式
本文介紹了創(chuàng)建Java項目的步驟,首先,點擊NewProject和EmptyProject并選擇Next,然后修改項目名,新建模塊和包,接著,在src右鍵點擊New新建JAVA類,最后點擊回車鍵即可創(chuàng)建成功,本文為個人經(jīng)驗總結(jié)2026-05-05
SpringBoot使用Redis實現(xiàn)分布式緩存
這篇文章主要介紹了SpringBoot redis分布式緩存實現(xiàn)過程解析,文中通過示例代碼解析的非常詳細,感興趣的同學(xué)可以參考閱讀2023-04-04
java實現(xiàn)截取PDF指定頁并進行圖片格式轉(zhuǎn)換功能
這篇文章主要介紹了java實現(xiàn)截取PDF指定頁并進行圖片格式轉(zhuǎn)換功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
Java高效實現(xiàn)合并多個Word文檔的實戰(zhàn)指南
在企業(yè)開發(fā)和日常辦公自動化中,我們經(jīng)常需要處理 Word 文檔,本文將系統(tǒng)講解在 Java 中合并 Word 文檔的常用方法,提供完整示例,幫助你快速掌握文檔合并技巧2026-01-01

