技术文章2025 年 12 月 14 日约 2.5 分钟

Linux systemd 服务管理:从编写 unit 到故障排查

使用 systemd 管理自定义服务,覆盖 unit 文件、启动策略、日志查看和失败恢复。

systemd 已经是现代 Linux 的事实标准,但很多人的认知停留在 systemctl start/restart。这篇文章用「把一个 Node 服务做成开机自启」的完整过程,把 unit 文件、启动策略和排障讲透。

#unit 文件:三段各管什么

以 /etc/systemd/system/myapp.service 为例:

ini
[Unit]
Description=My App Service
After=network-online.target redis.service
Wants=network-online.target

[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/.env
ExecStart=/usr/bin/node /opt/myapp/dist/server.js
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
TimeoutStartSec=30
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
  • [Unit]:描述、依赖。After= 只保证顺序,不保证服务已就绪;真正要等「就绪」得用 Type=notify 或 socket 激活,后面再说。
  • [Service]:怎么跑、跑挂了怎么办。Type=simple 表示 ExecStart 一启动就算 running,适合长驻进程。
  • [Install]:WantedBy=multi-user.target 配合 enable 实现开机启动。

改完 unit 必须 systemctl daemon-reload,否则 systemd 还用旧配置——这是新手最常犯的错,报错还是「Unit myapp.service not found」,其实是没 reload。

#重启策略:别让服务死在半夜

Restart=on-failure 表示只有异常退出才重启;on-abnormal 只在被信号杀死时重启。再配合:

  • RestartSec=5:崩溃后等 5 秒再拉起,防止「秒崩-秒启」风暴。
  • StartLimitBurst=5 + StartLimitIntervalSec=60:60 秒内最多重启 5 次,超过就放弃并进入 failed 状态——这个保护是必须的,没有它,一个配置错误的服务会把 CPU 打满在无意义的循环重启上。
  • 进程里要正确处理 SIGTERM:优雅关连接、刷盘、再退出。systemd 发 SIGTERM 后等 TimeoutStopSec(默认 90s),超时才 SIGKILL。

#排障:journalctl 是主战场

服务起不来,第一步永远先看日志,别急着改配置:

bash
systemctl status myapp          # 状态 + 最近日志
journalctl -u myapp --since "10 minutes ago"
journalctl -u myapp -f          # 跟随
journalctl -u myapp -p err      # 只看错误级

常见的几类失败和它们的日志特征:

  • Failed at step EXEC spawning /usr/bin/node: No such file or directory:ExecStart 路径错了,或 User= 指定的用户无权访问。which node 确认绝对路径。
  • 启动后立刻 Main process exited, code=exited, status=1/:业务代码崩了,看应用日志。Restart 会自动拉起,但如果 StartLimitBurst 被打满,状态会停在 failed。
  • 端口占用:ss -tlnp 看谁占了,多半是上次进程没退干净。KillSignal=SIGTERM 下有些进程不退,可以在 ExecStop 里加 ExecStop=/bin/kill -TERM $MAINPID 或直接 KillMode=mixed。

#开机自启的完整姿势

bash
sudo systemctl daemon-reload
sudo systemctl enable --now myapp    # enable 开机自启 + 立即启动
sudo systemctl is-enabled myapp      # enabled
sudo systemctl list-units --type=service --state=running | grep myapp

enable --now 是我最常用的组合:一条命令同时完成注册和启动。最后提醒一句:生产环境改服务配置,先 systemctl cat myapp 确认 systemd 眼里实际的配置,防止你改的文件根本不在生效路径上(比如有的人改了 /etc/init.d/ 下的旧脚本,systemd 根本不看)。

写于 2025 年 12 月 14 日

栏目
技术文章
约
2.5 分钟
字数
2.1K
阅读
216

本文为原创记录,转载请注明出处。如果这篇替你省了时间,欢迎留言说说你踩到的坑。

同题 · related

留言 · remarks

00 条

还没有留言,来说点什么吧。

Linux systemd 服务管理:从编写 unit 到故障排查 · LXH·BLOG