从入门到生产级实战指南
目录导读
- 为什么需要进程监控脚本 —— 守护进程的核心价值
- 基础版:Shell 脚本实现进程守护 —— 5 行代码搞定
- 进阶版:Python 脚本带日志与告警 —— 企业级必备
- 常用技巧与陷阱规避 —— 避免僵尸进程、误判与死循环
- 高频问答(FAQ) —— 解决你最常见的困惑
为什么需要进程监控脚本
在服务器运维中,进程崩溃或假死是家常便饭,无论是 Node.js 应用、Java 服务还是数据库,一旦进程意外退出,就会导致服务不可用,手动重启不仅效率低,且无法做到 7×24 小时响应。监控进程并自动重启的脚本成为运维工程师的必备技能,它不仅能减少人工干预,还能在故障发生时快速恢复,是保障系统高可用性的第一道防线。

基础版:Shell 脚本实现进程守护
最简单的方式是使用 while 循环 + pgrep 检查进程是否存在,以下脚本适用于大多数 Linux 环境:
#!/bin/bash
PROCESS_NAME="myapp" # 替换为你的进程名
while true; do
if ! pgrep -f "$PROCESS_NAME" > /dev/null; then
echo "$(date) - $PROCESS_NAME 未运行,正在重启..." >> /var/log/process_monitor.log
nohup /path/to/your/app > /dev/null 2>&1 &
fi
sleep 10 # 每10秒检查一次
done
工作原理:pgrep 查找进程,如果找不到( 取反),则执行启动命令。nohup 保证应用在后台运行且不受终端关闭影响,这个脚本虽简单,但已具备基本监控能力。
进阶版:Python 脚本带日志与告警
生产环境中,仅有重启还不够,我们往往需要记录日志、发送告警,并避免重复启动,以下是一个 Python 版本,更适合复杂需求:
import subprocess
import time
import logging
import smtplib
from email.mime.text import MIMEText
logging.basicConfig(filename='/var/log/my_monitor.log', level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
def send_alert(process_name):
msg = MIMEText(f"进程 {process_name} 已崩溃,系统已自动重启。")
msg['Subject'] = f"[告警] {process_name} 重启通知"
msg['From'] = "monitor@example.com"
msg['To'] = "ops@example.com"
# 此处省略SMTP连接代码,可按需配置
def is_running(pid_file):
try:
with open(pid_file, 'r') as f:
pid = int(f.read().strip())
return pid, subprocess.run(['kill', '-0', str(pid)], capture_output=True).returncode == 0
except (FileNotFoundError, ValueError):
return None, False
def start_process(cmd, pid_file):
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
with open(pid_file, 'w') as f:
f.write(str(proc.pid))
return proc.pid
if __name__ == '__main__':
CMD = "python /opt/myapp/app.py" # 你的启动命令
PID_FILE = "/tmp/myapp.pid"
while True:
pid, running = is_running(PID_FILE)
if not running:
logging.warning("进程未运行,尝试重启...")
new_pid = start_process(CMD, PID_FILE)
logging.info(f"已重启,新PID: {new_pid}")
send_alert("myapp") # 可选
time.sleep(15)
亮点:通过 PID 文件精准判断,避免误杀其他同名进程;集成了日志和邮件告警;使用 kill -0 检查进程是否存活(不发送信号,仅检测存在性)。
常用技巧与陷阱规避
- 避免死循环误判:若应用启动需要较长时间,可在启动后加
sleep 5再进入下一次检查,防止因启动延迟导致重复拉起。 - 防止僵尸进程:使用
double-fork或setsid技术,确保子进程不被父进程退出影响。 - 资源占用限制:可结合
ulimit或systemd的MemoryMax控制异常内存增长。 - 更现代的选择:生产环境推荐使用 systemd service 或 Supervisor,它们内置自动重启及故障转移策略,脚本适合轻量级或临时任务。
高频问答(FAQ)
Q1: 脚本本身崩溃了怎么办?
A: 可将脚本设置为 cron 任务,每分钟执行一次,并在脚本内做单实例锁(如 flock 命令),防止多个副本同时运行。
Q2: 如何让脚本开机自启?
A: 将启动命令写入 /etc/rc.local,或编辑 /etc/systemd/system/monitor.service 创建守护服务。
Q3: 进程被 kill -9 杀掉后,kill -0 能检测到吗?
A: 可以。kill -0 检查的是 PID 是否存在,僵尸进程会返回成功,因此建议结合 ps -o stat= 查看进程状态是否为 Z。
Q4: 能否用 Docker 实现类似效果?
A: 可以,Docker 自带 --restart=always 参数,但注意容器内进程监控与宿主机维度不同,且重启策略不含健康检查,复杂场景可结合 docker-compose + healthcheck。
延伸建议:若你管理的服务较多,推荐使用 Supervisor 的进程组管理功能,或 Kubernetes 中的 livenessProbe(探针),脚本方案更适合作为轻量化兜底,两者结合能构建更健壮的监控体系。