title: "Linux Jar包配置Systemd自启动实战:从排查到配置全流程"
tags:
- Linux
- systemd
- Java
- 运维
- 自启动
categories: - 运维
description: "生产环境 Jar 包没有配置自启动?本文从实际排查经验出发,教你如何确认 Jar 是否自启、排查启动方式、编写 Systemd Service 配置开机自启动,包含 forking 和 simple 两种模式的实战配置。"
导读:前几天在生产服务器上发现两个 Java 服务跑了好几年,但从来没配过自启动------服务器一旦重启就完了。这篇文章把整个排查和配置过程记录下来,方便以后遇到类似情况直接照做。
一、事情是怎么发现的
事情起因很简单:线上有一台转码服务器,上面跑了两个 Java 服务。我上去检查的时候,习惯性地看了一眼自启动配置,结果发现------啥都没配。
这台机器上次重启还是 2021 年 7 月,快 5 年没重启过了。jar 进程还在跑,纯粹是因为没重启过。万一哪天硬件故障或者需要重启,服务就起不来了。
这种事在生产环境其实挺常见的:部署的时候赶进度,手动 nohup java -jar xxx & 一把梭,服务跑起来就完事了。自启动?以后再说。然后就没有以后了。
二、排查过程
第一步:确认有哪些 Java 进程在跑
bash
jps
输出:
103856 Jps
64194 sdcs-dtc.jar
240473 tsingtao-server.jar
两个 jar 都在跑。
第二步:检查有没有 Systemd 服务
bash
grep -r "sdcs-dtc" /etc/systemd/system/
grep -r "tsingtao-server" /etc/systemd/system/
没有任何输出,说明没有配置 systemd 服务。
第三步:检查其他自启动方式
bash
# rc.local
cat /etc/rc.local
# → 只有默认的 touch /var/lock/subsys/local,没有 jar 启动命令
# crontab
crontab -l | grep "@reboot"
# → 无输出
# supervisor
ls /etc/supervisord.d/
# → 目录不存在
全都没有。结论:这两个 jar 是手动启动的,开机不会自动运行。
第四步:查看进程详情
bash
ps -ef | grep -E "sdcs-dtc|tsingtao-server"
关键信息:
- 两个进程的 PPID 都是 1(父进程是 init/systemd)
sdcs-dtc.jar从 2023 年跑到现在tsingtao-server.jar从 2025 年跑到现在
第五步:检查服务器重启历史
bash
last reboot
输出显示最近一次重启是 2021 年 7 月 21 日。怪不得 jar 还在跑------服务器根本没重启过。
第六步:找到启动脚本
bash
ls /data/conver/distribution/bin/
shutdown.sh startup.sh
原来有现成的启停脚本。看看脚本里怎么写的:
bash
grep -E "nohup|&" /data/conver/distribution/bin/startup.sh
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup $JAVA ${JAVA_OPT} yxt.dtc >> ${BASE_DIR}/logs/start.out 2>&1 &
脚本用了 nohup ... & 后台启动,这个信息后面配置 systemd 时要用到。
三、编写 Systemd Service
有现成的启停脚本,service 配置就简单了。关键是要选对 Type:
| Type | 适用场景 |
|---|---|
simple |
进程前台运行,不 fork |
forking |
脚本里有 & 或 nohup,进程后台运行 |
因为 startup.sh 里用了 nohup ... &,所以用 Type=forking。
创建 service 文件
bash
cat > /etc/systemd/system/conver.service << 'EOF'
[Unit]
Description=Conver Distribution Service
After=network.target
[Service]
Type=forking
User=root
ExecStart=/data/conver/distribution/bin/startup.sh
ExecStop=/data/conver/distribution/bin/shutdown.sh
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
Type |
forking |
startup.sh 用 nohup 后台启动 |
After |
network.target |
网络就绪后再启动 |
ExecStart |
启动脚本路径 | 用现成的 startup.sh |
ExecStop |
停止脚本路径 | 用现成的 shutdown.sh |
Restart |
on-failure |
异常退出时自动重启 |
RestartSec |
10 |
重启前等 10 秒 |
WantedBy |
multi-user.target |
开机自启到多用户模式 |
⚠️ 如果你的 jar 是直接
java -jar前台运行的(没有&),把Type改成simple,ExecStart直接写完整的 java 命令。
如果没有启停脚本
如果项目没有现成的 startup.sh,可以直接把 java 命令写进去:
bash
cat > /etc/systemd/system/conver.service << 'EOF'
[Unit]
Description=Conver Distribution Service
After=network.target
[Service]
Type=simple
User=root
ExecStart=/bin/java -server -Xms2g -Xmx2g \
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m \
-jar /data/newconver/tsingtao-server/target/tsingtao-server.jar \
--spring.config.location=file:/data/newconver/tsingtao-server/conf/application-config.yml
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
这种方式用 Type=simple,systemd 直接管理 java 进程,更干净。
四、启用自启动
bash
# 1. 先停掉手动启动的旧进程
kill 64194 240473
# 2. 确认停干净了
jps
# 3. 重新加载 systemd 配置
systemctl daemon-reload
# 4. 设置开机自启
systemctl enable conver
# 5. 启动服务
systemctl start conver
# 6. 验证
systemctl status conver
systemctl is-enabled conver
is-enabled 输出 enabled 就说明配置成功了。
五、常用管理命令速查
| 操作 | 命令 |
|---|---|
| 启动服务 | systemctl start conver |
| 停止服务 | systemctl stop conver |
| 重启服务 | systemctl restart conver |
| 查看状态 | systemctl status conver |
| 查看是否自启 | systemctl is-enabled conver |
| 启用自启 | systemctl enable conver |
| 禁用自启 | systemctl disable conver |
| 查看日志 | journalctl -u conver -f |
| 重新加载配置 | systemctl daemon-reload |
💡 修改了 service 文件后,一定要执行
systemctl daemon-reload重新加载,否则改了不生效。
六、常见问题
Q:Type=forking 和 Type=simple 怎么选?
看你的启动脚本。脚本里有 & 或 nohup ... &,用 forking。如果 ExecStart 直接写 java -jar 命令(前台运行),用 simple。选错了的表现:simple 配了 forking 的脚本,systemd 会认为服务一直处于 activating 状态;反过来,forking 配了 simple 的命令,systemd 认为服务立即退出了。
Q:forking 模式下 systemd 怎么跟踪进程?
systemd 会跟踪 ExecStart 脚本 fork 出来的子进程。如果脚本 fork 了多个后台进程,可能需要加 PIDFile 指定 PID 文件路径,让 systemd 知道跟踪哪个。
Q:Restart=on-failure 和 Restart=always 有什么区别?
on-failure 只在异常退出(非 0 返回码)时重启,always 不管什么原因退出都重启(包括正常 stop)。生产环境建议用 on-failure,避免 systemctl stop 之后又被自动拉起来。
Q:怎么确认服务器重启后 jar 真的会自动起来?
最稳妥的办法:在测试环境配好后重启一次验证。生产环境不敢随便重启的话,至少确认 systemctl is-enabled 输出 enabled,并且 systemctl status 显示 active (running)。
Q:日志怎么看?
bash
# 实时看 systemd 日志
journalctl -u conver -f
# 看最近 100 行
journalctl -u conver -n 100
如果 jar 自己有日志输出(比如 Spring Boot 的 logback),那些日志在 jar 的 logs 目录下,不在 systemd 日志里。
参考链接
写了这么多,如果对你有帮助的话,给我点个赞 👍 收个藏 📌 吧~
如果你也遇到过生产环境 jar 没配自启动的坑,或者有更好的 systemd 配置方案,欢迎在评论区分享,我会一一回复。