CentOS 上的业务进程意外挂掉,运维没及时发现,导致服务中断被客户投诉,这是生产环境里最让人头疼的问题之一。解决这个问题的核心思路不是“盯着看”,而是建立一套自动拉起机制,让系统自己完成检测和恢复。下面直接讲具体方案,从最简单的到最稳健的,你可以根据场景选用。

方案一:Systemd 自带的重启策略

如果你的 CentOS 版本是 7 或更高,Systemd 已经是默认的初始化系统,它内置了强大的进程监控和自动拉起功能,这是最标准、最推荐的方式。很多人只把 Systemd 当成开机启动工具,却忽略了它的 "Restart" 系列参数。

你需要为你的进程编写一个 service 文件,通常放在 "/etc/systemd/system/" 目录下,例如 "myapp.service"。核心配置如下:

[Unit]
Description=My Application Service
After=network.target

[Service]
Type=simple
User=nobody
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/start.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

这里的 "Restart=always" 是关键,它表示无论进程以什么状态退出,Systemd 都会尝试重启它。"RestartSec=10" 设置了两次重启之间的间隔为 10 秒,防止进程反复崩溃导致系统资源被耗尽。如果你的进程支持优雅退出,还可以加上 "KillSignal=SIGTERM" 和 "TimeoutStopSec=30" 来确保停止时能完成收尾工作。

配置完成后执行 "systemctl daemon-reload" 重载配置,再用 "systemctl enable myapp" 设置开机启动,最后 "systemctl start myapp" 启动服务。你可以用 "kill -9" 杀掉进程测试一下,几秒后它会自动恢复。Systemd 还会通过 cgroups 跟踪进程树,即使主进程产生了子进程,也能彻底清理干净,这是比传统双 fork 守护进程更可靠的地方。

方案二:Supervisor 进程管理器

如果你的 CentOS 版本较老,或者你管理的是 Python、Node.js 这类应用,Supervisor 是一个轻量且成熟的选择。它由 Python 编写,配置简单,能提供比 Systemd 更细粒度的进程控制。

安装只需一条命令:"yum install supervisor",如果是离线环境可以下载 RPM 包手动安装。安装后主配置文件在 "/etc/supervisord.conf",通常建议在 "/etc/supervisord.d/" 目录下为每个程序单独创建配置文件。一个典型的配置如下:

[program:myapp]
command=/opt/myapp/start.sh
directory=/opt/myapp
user=nobody
autostart=true
autorestart=true
startsecs=5
startretries=3
redirect_stderr=true
stdout_logfile=/var/log/myapp/stdout.log
stderr_logfile=/var/log/myapp/stderr.log

"autorestart=true" 让进程意外退出时自动拉起,"startsecs=5" 表示进程启动后需要稳定运行 5 秒才算成功,如果 5 秒内崩溃,Supervisor 会认为启动失败并重试。"startretries=3" 限制了连续启动失败的最大次数,超过后不再尝试,避免无限循环。Supervisor 自带一个命令行工具 "supervisorctl",你可以用它执行 "status"、"restart"、"tail" 等操作,非常方便日常运维。它还提供一个简单的 Web 管理界面,在配置文件中启用 "[inet_http_server]" 即可,适合在内网中集中管理多台机器的进程。

方案三:Shell 脚本轮询监控

有时候你不方便引入额外组件,或者只需要临时顶一下,可以用 Shell 脚本实现一个轻量的守护进程。核心逻辑是死循环加进程检测,下面是一个生产可用的脚本模板:

#!/bin/bash
PROCESS_NAME="myapp"
START_CMD="/opt/myapp/start.sh"
CHECK_INTERVAL=10
MAX_RETRY=3
RETRY_COUNT=0

while true; do
    # 检测进程是否存在
    if ! pgrep -x "$PROCESS_NAME" > /dev/null; then
        echo "[$(date)] $PROCESS_NAME is down, attempting to restart..."
        $START_CMD &
        sleep 5
        
        # 验证启动是否成功
        if pgrep -x "$PROCESS_NAME" > /dev/null; then
            echo "[$(date)] $PROCESS_NAME restarted successfully."
            RETRY_COUNT=0
        else
            RETRY_COUNT=$((RETRY_COUNT + 1))
            echo "[$(date)] Restart failed, retry count: $RETRY_COUNT"
            if [ $RETRY_COUNT -ge $MAX_RETRY ]; then
                echo "[$(date)] Max retry reached, sending alert..."
                # 在这里调用告警接口或发送邮件
                exit 1
            fi
        fi
    fi
    sleep $CHECK_INTERVAL
done

这个脚本用 "pgrep -x" 精确匹配进程名,避免了误判。它加入了重试上限和告警逻辑,防止进程反复拉起失败时脚本自己静默失效。你可以把它放到后台运行 "nohup ./guard.sh &",或者更规范地注册为 Systemd 服务。不过这种脚本方式有几个硬伤:它无法追踪子进程,如果目标进程 fork 到后台后父进程退出,脚本会误判;另外轮询本身有延迟,做不到秒级恢复。所以它只适合非关键业务的临时方案,长期运行还是应该用 Systemd 或 Supervisor。

方案四:Monit 全功能监控拉起

Monit 是一个轻量级的系统监控工具,不仅能监控进程存活,还能检查文件完整性、系统资源、网络连接等,并在触发条件时执行自动修复动作。在 CentOS 上安装 "yum install monit",配置文件 "/etc/monitrc"。一个监控进程的配置如下:

check process myapp with pidfile /var/run/myapp.pid
    start program = "/opt/myapp/start.sh"
    stop program = "/opt/myapp/stop.sh"
    if does not exist then restart
    if 5 restarts within 5 cycles then timeout
    if cpu usage > 90% for 5 cycles then restart
    if memory usage > 1 GB for 5 cycles then alert

Monit 的优势在于条件判断非常灵活。你可以设置“进程不存在时重启”、“CPU 超过 90% 持续 5 个周期就重启”、“内存超过 1GB 就发告警”等组合策略。它还内置了 HTTP 状态页面,能直观看到所有受管资源的状态。Monit 自身以守护进程方式运行,它监控的进程如果挂了,Monit 会立即执行重启命令。但要注意,Monit 依赖 PID 文件来判断进程状态,你的应用程序必须正确生成 PID 文件,否则 Monit 无法准确检测。

方案五:Kubernetes 的自动重启机制

如果你的 CentOS 环境已经容器化并运行着 Kubernetes,那进程自动拉起就是平台自带的能力,不需要额外配置守护进程。Kubernetes 通过 Pod 的 "restartPolicy" 控制重启行为,默认值就是 "Always",意味着容器一旦退出,kubelet 会立刻尝试重启它。你可以通过 Deployment 的 "livenessProbe" 进一步精细化检测:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

这个配置让 kubelet 每隔 10 秒对你的应用发起 HTTP 健康检查,连续 3 次失败就判定容器不健康,触发重启。相比只看进程是否存在,健康检查能发现“进程活着但服务已不可用”的假活状态,这是传统进程监控做不到的。Kubernetes 的控制器还会保证你声明的副本数,即使整台机器宕机,Pod 也会被调度到其他节点上运行,这是自愈能力的最高级别。

如何选择适合你的方案

这么多方案摆在面前,选哪个取决于你的实际场景。如果你的 CentOS 7+ 系统只跑几个自研服务,Systemd 就是最佳选择,零依赖、配置标准化、和系统深度集成。如果你管理着一批 Python 或 Node.js 应用,希望有一个统一的进程管理界面,Supervisor 会更顺手。如果你需要同时监控系统资源并在异常时自动重启进程,Monit 的一体化能力很合适。容器化环境就直接用 Kubernetes 的原生机制,不要再在容器里套 Supervisor 这种反模式。临时救急可以用 Shell 脚本,但一定要记得后续迁移到正式方案。

生产环境的避坑要点

自动拉起不是配置完就万事大吉,有几个坑一定要避开。第一,一定要设置重启间隔和重试上限,否则进程反复崩溃会导致重启风暴,把 CPU 和内存打满。第二,日志要保留,Systemd 的 journal、Supervisor 的日志文件、Monit 的事件记录,都是你事后排查“进程为什么会挂”的关键线索。第三,拉起失败要有告警,无论你用的是哪种方案,都要对接邮件、钉钉、企业微信或内部告警平台,让值班人员知道自动拉起已经达到上限,需要人工介入。第四,启动脚本必须是幂等的,因为自动拉起会多次执行启动命令,如果脚本里没有做互斥判断,可能会启动多个实例导致数据错乱。第五,定期做故障演练,主动 kill 掉生产进程,验证拉起机制是否按预期工作,告警是否及时送达。

把进程自动拉起这件事做扎实,你的 oncall 手机会安静很多。