systemd服务配置核心是正确编写.service文件的重启策略:type=forking用于程序自行后台化,restart=always需配合startlimitinterval=0防停机,user/group权限、绝对路径、journald日志等缺一不可。

systemd 服务配置:现代发行版首选
用 systemd 配置进程守护,核心是写对 .service 文件里的重启策略。它不依赖额外进程,直接由 init 系统接管,稳定性高、日志集成好。
常见错误是把 Type=forking 和 Type=simple 搞混:程序自己后台化(比如加 & 或调用 daemon())必须用 Type=forking,否则 systemd 会误判进程已退出,立刻触发重启。
-
Restart=always覆盖所有退出场景,但若进程 5 秒内连续崩溃 5 次,默认会停机——得配StartLimitInterval=0关掉频率限制 -
RestartSec=10是硬性等待,不是“延迟启动”,而是防高频闪退打满 CPU -
User=和Group=必须真实存在,且该用户对ExecStart中的二进制和工作目录有执行权限 - 日志默认走
journald,查日志别用tail -f,直接journalctl -u myapp.service -f
supervisord 静默失败排查:四类硬性条件缺一不可
supervisord 不报错、不写日志、supervisorctl start 返回 ERROR (no such process)?大概率是以下四个条件没同时满足:
-
command必须是绝对路径,~/bin/app或$HOME/bin/app都无效;Java 要写/usr/bin/java -jar xxx.jar,Python 要写/usr/bin/python3 script.py -
directory对应路径必须mkdir -p创建好,且user对该目录有r-x权限(cd进去得成功) -
stdout_logfile和stderr_logfile的父目录(比如/var/log/myapp/)必须手动创建,supervisord 只建文件,不建目录 -
user字段指定后,该用户必须能执行command中的程序(如www-data不能直接跑/root/script.sh)
主配置里 [include] 的 files = /etc/supervisor/conf.d/*.conf 路径也得真实存在,否则整个 include 段被忽略。
pm2 自动重启失效:不是所有崩溃都算“退出”
pm2 的 autorestart: true 只响应进程退出事件,但 Linux 的 OOM Killer 杀进程时发的是 SIGKILL,不走正常退出流程,pm2 就感知不到。
真正容易被忽略的是 min_uptime 和 max_restarts 的组合逻辑:如果应用启动 2 秒就崩,min_uptime=5000 就会让这次重启不计入稳定周期,反复触发“不稳定状态”,最终 pm2 主动停掉重启。
- 内存超限自动重启靠
max_memory_restart: '512m',但得确认ulimit -v没设太低,否则进程根本起不来 -
watch: true在生产环境等于自毁,文件变更会强制 reload,哪怕只是改了个日志级别 - 集群模式下,
pm2 restart all不等价于单实例重启,要留意instance_var是否冲突
别踩 shell + crontab 的坑:临时验证可以,长期别用
用 ps aux | grep myapp + nohup 启动,再靠 crontab 每分钟扫一次——这种方案在负载高或进程刚启动就崩溃时,会出现 59 秒空白窗口。
更隐蔽的问题是信号干扰:grep myapp 本身会出现在 ps 结果里,不加 -v grep 就永远“检测到进程在运行”,实际早挂了。
- 真正要用脚本兜底,至少加
pgrep -f '^/path/to/myapp$'精确匹配命令行 -
nohup启动后记得重定向1>/dev/null 2>&1 &,否则 stdout/stderr 会卡住子进程 - 脚本里别用
sleep做延时,crontab 本身就有调度间隔,重复延时会导致检查滞后
复杂点在于:没有统一日志位置、无法查历史重启次数、没法做资源限制——这些事交给 systemd 或 supervisord 更省心。











