Supervisor 进程重启策略
解读
国内一线/二线互联网公司 PHP 面试中,Supervisor 几乎是“标配”考点。面试官问“重启策略”并不是让你背参数,而是想确认三件事:
- 你是否真的在生产环境用过 Supervisor 兜底 PHP 常驻进程(Queue、WebSocket、Swoole、Gearman 等);
- 能否根据业务 SLA 选择“立即重启”还是“延迟重启”,并给出可落地的配置;
- 是否理解 Supervisor 重启与 systemd、Docker restart-policy 的差异,避免“拍脑袋”混用。
如果只能答“autorestart=true”,会被判定为“纸上谈兵”;只有把 autorestart、startretries、startsecs、exitcodes、stopsignal、stopwaitsecs、killasgroup、user、environment 串成“高可用方案”,才算及格。
知识点
-
重启触发条件
- 进程退出码在 exitcodes 白名单内 → 不重启;
- 退出码不在白名单,或收到 uncaught signal → 进入重启逻辑;
- 手动 supervisorctl restart/stop → 不受 autorestart 影响。
-
重启节奏控制
- startretries:连续重启次数,默认 3;超过后进入 FATAL 状态,需人工干预;
- startsecs:进程启动后保持运行多少秒才认为“成功”,默认 1;短作业建议 3
5 s,长连接服务建议 1030 s; - minfds / minprocs:系统资源兜底,防止疯狂 fork 打爆服务器。
-
优雅退出
- stopsignal:默认 TERM,Swoole/Laravel Queue 建议改为 QUIT,让 Worker 把当前 job 处理完再退出;
- stopwaitsecs:等待优雅退出的最大时间,超时后 Supervisor 会强制 KILL;
- killasgroup=true:把信号发给整个进程组,防止子进程变僵尸。
-
资源与权限隔离
- user=www-data:避免 PHP 进程以 root 启动被攻击者 getshell;
- environment=PATH="/usr/local/bin:/usr/bin",APP_ENV="prod":显式注入环境变量,防止系统升级后找不到 php 二进制。
-
与 systemd 的差异
- Supervisor 自带 Web UI 和 XML-RPC 接口,方便 PHP 脚本动态重启 Worker;
- systemd 的 Restart=always 没有“启动成功”概念,只要进程退出就重启,不适合需要“预热”的 PHP 业务;
- 在 Kubernetes 场景,重启策略应下沉到 Pod level,Supervisor 只负责单容器内多进程管理,避免“双重重启”竞态。
-
国内云主机特殊注意
- 阿里云轻量、腾讯云 Lighthouse 默认关闭 swap,若 PHP Worker 内存泄漏,重启策略必须配合 memory_limit + max_requests,否则 OOM 后可能直接被杀进程,Supervisor 来不及重启;
- 华为云 CCE 节点会定期镜像升级,/var/log/supervisor 建议挂载到云盘,防止日志丢失导致无法定位重启原因。
答案
生产级 Supervisor 进程重启策略可按“三段式”落地:
- 配置模板(/etc/supervisor/conf.d/laravel-queue.conf)
[program:laravel-queue]
command=/usr/local/bin/php /data/web/artisan queue:work --sleep=3 --tries=3 --max-time=3600
process_name=%(program_name)s_%(process_num)02d
numprocs=8
directory=/data/web
user=www-data
autorestart=true
startretries=5
startsecs=10
stopsignal=QUIT
stopwaitsecs=30
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-queue.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
environment=APP_ENV="prod",PATH="/usr/local/bin:/usr/bin"
-
重启策略解读
- autorestart=true:异常退出必重启;
- startretries=5 + startsecs=10:最多连续重启 5 次,每次必须稳定运行 10 秒才算成功,防止脚本瞬间崩溃导致 CPU 打满;
- stopsignal=QUIT + stopwaitsecs=30:发布代码时执行
supervisorctl restart laravel-queue:*,旧 Worker 会先把当前 job 消费完,30 s 内平滑退出,保证业务无断流; - killasgroup=true:若 Worker fork 了子进程(如 imagick 生成缩略图),一并杀掉,避免僵尸;
- user=www-data + 环境变量:符合等保 2.0 最小权限要求,同时解决 crontab 找不到 php 路径的“经典坑”。
-
监控与兜底
- 在 Prometheus + Grafana 中采集
supervisor_up{program="laravel-queue"},若出现 0 持续 2 分钟立即告警到飞书; - 每早 8 点定时执行
supervisorctl status | grep FATAL,若存在 FATAL 状态则触发 Ansible Playbook 拉取最新镜像并重载配置,实现“无人值守”修复; - 日志中若出现 “gave up” 关键字,说明 startretries 耗尽,自动创建 Jira 工单并 @PHP 负责人,防止沉默失败。
- 在 Prometheus + Grafana 中采集
拓展思考
-
灰度重启 大促期间不能全量重启 200 个 Queue Worker,可写 PHP 脚本调用 Supervisor XML-RPC 接口,每次只重启 10%,并监听队列积压长度,若 lag 超过 5 万则暂停继续重启,实现“灰度滚动”。
-
与 Swoole 热重载结合 Swoole Server 自带 reload,但只能重载 Worker 进程,Master 进程仍需 Supervisor 看护。此时把
stopsignal=USR1并设置stopwaitsecs=60,可实现“代码热更新”而 Supervisor 不退出,兼顾性能与稳定性。 -
多机房容灾 在双活架构中,A 机房 Supervisor 若检测到 MySQL 主库不可写,可通过 eventlistener 脚本把队列进程数动态缩容到 0,避免大量失败 job 堆积;B 机房正常消费,等 A 机房数据库恢复后再自动扩容,实现“跨机房熔断”。
-
合规审计 国内金融项目要求“运维可审计”,可在 Supervisor 之上加一层 OPACL(Open Policy Agent for Linux),所有 restart/stop 操作必须携带工单号,否则 API 返回 403;面试时提到这一点,可瞬间拉开与普通候选人的差距。