目录
- 一个故(shi)事(gu)
- 方案一:systemd配置(推荐)
- 什么是systemd?
- 实战步骤:从0到1配置
- 1. 准备SpringBoot应用
- 2. 创建启动脚本(关键)
- 3. 创建systemd服务文件
- 4. 服务管理命令
- 避坑指南
- 坑1:权限问题导致启动失败
- 坑2:应用启动慢导致超时
- 坑3:优雅关闭不生效
- 方案二:Supervisor配置(兼容更多系统)
- 安装Supervisor
- 创建应用配置文件
- Supervisor管理命令
- 两种方案对比与选择建议
- 高级配置:健康检查与自动恢复
- systemd健康检查
- 防止无限重启策略
- 总结
一个故(shi)事(gu)
"小王,生产环境怎么回事?服务全挂了!"
上个月一个周六的凌晨,小王被这通电话惊醒。
机房意外断电,恢复供电后所有服务器重启,但我们的SpringBoot应用没有自动启动,导致业务中断了整整40分钟。
事后排查发现,是之前的运维同事离职时没有留下开机自启动配置文档。更糟的是,应用运行中偶尔会因为OOM崩溃,也没有任何进程守护机制。
经历这次事故后,小王整理了两套SpringBoot应用开机自启动与进程守护方案,在生产环境稳定运行至今。
方案一:systemd配置(推荐)
什么是systemd?
简单说,systemd是现在linux系统的"大管家",负责管理系统启动和服务进程。
几乎所有主流Linux(Centos 、Ubuntu 、Debian等)都支持使用systemd。
为什么推荐它?因为:
原生集成:不需要额外安装软件 功能强大:支持开机自启、进程监控、日志管理 配置简单:一个服务文件搞定所有设置
实战步骤:从0到1配置
1. 准备SpringBoot应用
假设我们的应用信息:
- 应用名称:demo-app
- JAR文件路径:
/opt/apps/demo-app.jar
- 运行用户:appuser(建议使用非root用户)
- 日志路径:
/var/log/demo-app.log
2. 创建启动脚本(关键)
不要直接在systemd中调用Java命令!创建一个启动脚本/opt/apps/start.sh
:
#!/bin/bash # SpringBoot应用启动脚本 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 # 启动应用 echo "开始启动 $APP_NAME ..." nohup java $JVM_OPTS -jar $JAR_FILE --server.port=$SERVER_PORT > $LOG_FILE 2>&1 & # 等待应用启动 echo "等待应用启动,端口:$SERVER_PORT ..." for i in {1..30}; do if check_port; then echo "$APP_NAME 启动成功!android" echo "日志文件:$LOG_FILE" exit 0 fi sleep 1 done # 启动超时处理 echo "错误:$APP_NAME 启动超时!" echo "查看日志获取详细信息:tail -f $LOG_FjavascriptILE" exit 1
给脚本添加执行权限:
chmod +x /opt/apps/start.sh
3. 创建systemd服务文件
创建/etc/systemd/system/demo-app.service
:
[Unit] Description=Demo SpringBoot Application Documentation=https://example.com/docs After=network.target mysql.service # 依赖网络和MySQL服务启动后再启动 Wants=mysql.service # MySQL启动失败不影响本服务启动 [Service] User=appuser Group=appuser WorkingDirectory=/opt/apps ExecStart=/opt/apps/start.sh # 自定义停止命令(优雅关闭) 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优雅关闭状态码 Restart=always # 总是重启(异常退出时) RestartSec=5 # 重启间隔5秒 TimeoutStartSec=300 # 启动超时时间(5分钟) TimeoutStopSec=60 # 停止超时时间 Environment="SPRING_PROFILES_ACTIVE=prod" # 环境变量 Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk" [Install] WantedBy=multi-user.target # 多用户模式下启动
4. 服务管理命令
# 重载systemd配置(修改服务文件后必须执行) sudo systemctl daemon-reload # 启动服务 sudo systemctl start demo-app # 停止服务 sudo systemctl stop demo-app # 重启服务 sudo systemctl restarPSfzJaqfgt demo-app # 设置开机自启 sudo systemctl enable demo-app # 取消开机自启 sudo systemctl disable demo-app # 查看服务状态 sudo systemctl status demo-app # 查看服务日志 sudo journalctl -u demo-app -f # -f表示实时跟踪
状态检查示例:
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.lwww.devze.comog ]; 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:权限问题导致启动失败
现象:Job for demo-app.service failed because the control process exited with error code.
sudo chown -R appuser:appuser /opt/apps /var/log/demo-app.log
坑2:应用启动慢导致超时
现象:Failed to start Demo SpringBoot Application. Timeout was reached.
[Service] TimeoutStartSec=300 # 5分钟
坑3:优雅关闭不生效
现象:执行stop后应用立即退出,@PreDestroy
方法未执行
[Service] KillSignal=SIGTERM TimeoutStopSec=60
同时在SpringBoot配置文件中添加:
server: shutdown: graceful spring: lifecycle: timeout-per-shutdown-phase: 30s
方案二:Supervisor配置(兼容更多系统)
如果你的服务器是较老的Linux发行版(如CentOS 6),或者需要管理多个进程,Supervisor是个不错的选择。
它是python编写的进程管理工具,跨平台性好。
安装Supervisor
CentOS安装:
# 安装EPEL源 sudo yum install -y epel-release # 安装Supervisor sudo yum install -y supervisor # 启动并设置开机自启 sudo systemcjavascripttl start supervisord sudo systemctl enable supervisord
Ubuntu安装:
sudo apt-get update sudo apt-get install -y supervisor
创建应用配置文件
创建/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 # 启动失败重试次数 startsecs=10 # 启动后稳定运行10秒才算成功 redirect_stderr=true # 错误日志重定向到标准输出 stdout_logfile=/var/log/demo-app.log stdout_logfile_maxbytes=10MB # 日志文件大小限制 stdout_logfile_backups=10 # 日志备份数量 environment= SPRING_PROFILES_ACTIVE="prod", JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
Supervisor管理命令
# 重载配置(修改配置后执行) sudo supervisorctl update # 查看所有进程状态 sudo supervisorctl status # 启动应用 sudo supervisorctl start demo-app # 停止应用 sudo supervisorctl stop demo-app # 重启应用 sudo supervisorctl restart demo-app # 查看应用日志 sudo supervisorctl tail -f demo-app
实战经验: "Supervisor的日志轮转功能非常实用,但要注意单位是MB不是GB!另外,它本身也需要通过systemd来管理开机启动,有点套娃的感觉。"
两种方案对比与选择建议
特性 | systemd | Supervisor |
---|---|---|
系统集成 | 原生集成,无需额外安装 | 需要单独安装 |
配置复杂度 | 中等 | 简单 |
进程监控 | 支持 | 支持 |
多应用管理 | 配置文件分散 | 集中管理 |
跨平台性 | 仅Linux | Linux/Unix/MAC |
使用建议
生产环境首选systemd:原生、轻量、功能足够 多应用管理选Supervisor:集中配置,适合管理多个微服务 docker环境不需要:容器本身提供进程管理
高级配置:健康检查与自动恢复
systemd健康检查
创建健康检查脚本/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状态码: $result" exit 1 fi
修改服务文件添加健康检查
[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
"健康检查是防止'僵尸进程'的有效手段。我们可能会遇到应用进程存在但无法提供服务的情况,有了健康检查后,systemd会自动重启这类异常应用。"
防止无限重启策略
无论是systemd还是Supervisor,都需要配置重启限制,避免应用陷入重启循环:
systemd配置:
[Unit] StartLimitInterval=600 # 10分钟内 StartLimitBurst=5 # 最多重启5次 StartLimitAction=poweroff # 达到限制后关闭系统(极端情况)
Supervisor配置:
[program:demo-app] autorestart=unexpected # 仅意外退出时重启 exitcodes=0,143 # 正常退出状态码
总结
按照这些步骤配置后,你的SpringBoot应用将具备服务器重启或应用异常down掉后自动恢复的能力。
以上就是SpringBoot实现应用开机自启动与进程守护配置方案的详细内容,更多关于SpringBoot应用开机自启动与进程守护的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论