本文目录导读:

“进程守护”的核心目标是确保一个进程(通常是关键服务或后台程序)在意外退出(崩溃、被杀死、内存溢出等)后能够自动重启,并且在系统启动时自动拉起。
实现方式分为操作系统级和应用/代码级两大类。强烈建议优先使用操作系统级方案,它们更稳定、资源占用更低,且被业界广泛验证。
以下是几种主流实现方案,从推荐到具体代码实现:
操作系统级守护(最推荐)
Linux/Unix 系统:systemd (现代Linux标配)
绝大多数现代Linux发行版(CentOS 7+, Ubuntu 16.04+, Debian 8+)都使用systemd,你可以轻松地将自己的程序变成系统服务。
步骤:
-
创建服务文件:
/etc/systemd/system/myapp.service[Unit] Description=My Awesome Application After=network.target [Service] Type=simple # 你的程序路径和参数 ExecStart=/usr/local/bin/myapp --config /etc/myapp.conf # 程序工作目录 WorkingDirectory=/opt/myapp # 以哪个用户运行(推荐非root) User=myappuser Restart=always # 等待系统网络/其他服务就绪后再启动 RestartSec=5 # (可选) 限制资源,防止程序失控 LimitNOFILE=65536 MemoryLimit=512M [Install] WantedBy=multi-user.target
-
管理服务:
# 重新加载配置文件 sudo systemctl daemon-reload # 启动服务 sudo systemctl start myapp # 设置为开机自启 sudo systemctl enable myapp # 查看状态(包括重启记录) sudo systemctl status myapp # 查看日志 sudo journalctl -u myapp -f
- 优点:最标准、可靠,内置资源控制、日志管理、依赖管理。
- 缺点:仅限Linux系统。
Windows 系统:Windows Service(Windows服务)
可以开发一个Windows服务程序,或使用工具将普通exe包装成服务运行。
使用 sc 命令(简单直接)
-
安装服务(需要管理员权限的命令提示符):
sc create "MyAppService" binPath="C:\path\to\myapp.exe" start=auto
start=auto表示开机自启。
-
设置失败自动重启(关键):
sc failure "MyAppService" reset=86400 actions=restart/5000/restart/10000/restart/15000
含义:如果失败,等待5秒后重启,再失败等待10秒后重启,再失败等待15秒后重启,24小时(86400秒)后重置失败计数。
-
启动/停止/删除服务:
net start MyAppService net stop MyAppService sc delete MyAppService
使用 NSSM(Non-Sucking Service Manager,推荐新手)
NSSM是一个开源工具,能用图形界面或命令行将任何程序打包成服务,并且自带进程守护功能(检测到程序退出后自动重启)。
- 下载NSSM。
nssm install MyAppService,在弹出的图形界面中选择你的exe文件,并在"Process" -> "App Events" 或 "Shutdown" 标签下设置 “Restart” 行为。
- 优点:原生支持,无需额外运行时。
- 缺点:编写服务程序有门槛,使用
sc命令配置略复杂,NSSM解决方案非常成熟。
容器化守护:Docker/Kubernetes
现代微服务架构的主流选择。
-
Docker: 使用
--restart参数。docker run -d --restart=always --name myapp myimage
--restart常用值:no(默认),on-failure(失败才重启),always(总是重启,包括docker进程重启时),unless-stopped(总是重启,除非手动停止)。 -
Kubernetes: 使用
Deployment或StatefulSet,K8s的控制器(Controller)会声明式地确保Pod数量始终符合预期,Pod挂了会自动重建,这是最强大的守护机制。apiVersion: apps/v1 kind: Deployment spec: replicas: 1 # 始终运行一个副本 template: spec: containers: - name: myapp image: myimage restartPolicy: Always
应用/代码级守护(轻量级或临时方案)
当无法使用操作系统级方案(如在共享主机、受限环境)时,可以自己编写一个父进程来监视子进程。
Shell 脚本(Linux/Mac)
一个最简单的用Bash脚本实现的守护进程:
#!/bin/bash
# 你的程序路径
PROGRAM="/usr/local/bin/myapp"
PROGRAM_ARGS="--config /etc/myapp.conf"
# 心跳检测:如果程序挂了,马上重启
while true; do
echo "Starting $PROGRAM..."
# 启动程序,并等待其退出
$PROGRAM $PROGRAM_ARGS
# 程序退出了(正常或非正常)
EXIT_CODE=$?
echo "Program exited with code $EXIT_CODE at $(date). Restarting in 5 seconds..."
# 等待5秒后重启
sleep 5
done
- 使用:
chmod +x daemon.sh nohup ./daemon.sh & # 后台运行守护脚本
- 缺点:非常简陋,脚本本身也可能挂掉,没有日志管理,不支持开机自启(需要配合crontab @reboot)。
Python 代码实现(跨平台)
使用Python的subprocess模块:
import subprocess
import time
import sys
import os
PROGRAM = "/usr/local/bin/myapp"
PROGRAM_ARGS = ["--config", "/etc/myapp.conf"]
def run_daemon():
while True:
print(f"Starting {PROGRAM}...")
# 启动子进程
process = subprocess.Popen([PROGRAM] + PROGRAM_ARGS)
# 等待子进程结束(阻塞)
process.wait()
exit_code = process.returncode
print(f"Process exited with code {exit_code}. Restarting in 5 seconds...")
time.sleep(5)
if __name__ == "__main__":
# 可以处理一些信号,比如SIGTERM
try:
run_daemon()
except KeyboardInterrupt:
print("Daemon stopped by user.")
sys.exit(0)
- 优点:跨平台(Windows/Linux/Mac),逻辑可控。
- 缺点:Python本身是解释型语言,依赖Python运行环境;性能不如C/C++编写的系统服务;进程退出、资源管理需要小心。
语言内置特性(如Go的graceful restart)
一些现代语言提供了更优雅的进程管理方式。
-
Go语言: 通过
os/signal和exec包可以实现平滑重启(Zero-downtime restart),但这属于高级应用。 -
Node.js: 可以使用
pm2或forever。pm2本身就是一个功能强大的Node.js进程守护工具,可以做到自动重启、日志分割、负载均衡。npm install pm2 -g pm2 start app.js --name myapp pm2 startup # 设置开机自启 pm2 save
如何选择?
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 生产环境,标准Linux服务器 | systemd |
最可靠、最原生、最小资源占用,与系统深度集成。 |
| 生产环境,Windows服务器 | sc 命令 或 NSSM |
原生服务或成熟工具,确保跨用户会话稳定运行。 |
| 生产环境,云原生/微服务 | Docker (--restart=always) 或 Kubernetes |
容器化带来的隔离性、可移植性和强大的自动修复能力。 |
| 开发环境/快速验证 | Shell脚本 或 Python 脚本 | 快速写出来即可,无需系统权限。 |
| Node.js 应用 | pm2 |
功能强大,专为Node.js设计,监控、日志、集群管理一站式解决。 |
核心建议:
- 永远不要只依赖代码层面的
try-catch来守护进程,因为进程可能因系统信号(kill -9)、内存不足(OOM Killer)等原因直接被操作系统杀死,代码段根本来不及执行。 - 为你的守护进程添加日志,记录重启次数、重启原因、错误信息,方便排查问题。
- 设置重启延迟(
RestartSec或sleep),防止程序崩溃后立即无限重启,导致CPU 100%。 - 做好资源限制,防止守护的进程成为僵尸进程或消耗过多内存。 systemd 的
MemoryLimit和LimitNOFILE很有用。