失踪人口回归:Supervisor时隔三年再更新

时隔近三年,这款经典的进程管理工具终于迎来了更新。

最近偶然注意到Supervisor项目发布了新版本(4.3.0—2025.08.23),印象中这个项目已经很久没有动静了。于是特意去翻看了更新日志,才发现距离上个版本发布已经过去了两年零八个月。仔细阅读版本说明后,发现这次更新主要集中在性能优化和稳定性提升,主要包括了:

两项重要Bug修复:

  • CPU 使用率优化:修复了在某些情况下轮询器未注销已关闭的文件描述符,导致过度轮询、CPU 占用异常升高的问题。
  • 重启稳定性提升:修复了在重启期间若有 HTTP 请求可能导致“端口已被占用”错误的问题。

兼容性更新

  • 支持 Python 3.13:修复了仅在 Python 3.13 环境下会失败的单元测试。
  • 清理依赖关系:Python 3.8 及以上版本不再需要 setuptools 作为运行时依赖;Python 3.7 及以下版本仍需手动安装 setuptools。

时间飞逝,Supervisor已有近三年未发布版本了,而我也差不多有三年多没有使用这个组件了。正好借此机会,我将之前在使用过程中记录的笔记重新整理了一遍,分享给大家。

初识Supervisor:你的进程管理

Supervisor是用Python开发的一款用于Linux的进程管理工具,采用典型的C/S架构,够高效监控和管理进程状态。官方资源:Github仓库官方文档

Supervisor主要包含两个组件:

  • supervisord:服务端,负责启动、监控和管理子进程。

  • supervisorctl:客户端,提供命令行界面管理子进程。

主要特点:

  • 进程状态监控和管理
  • 进程崩溃自动重启
  • 统一的进程管理接口
  • Web管理界面支持
  • 进程组管理功能

注意事项:

  • Supervisor要求要离的程序必须非守护进程方式运行(例如:管理nginx,必须在 nginx 的配置文件里添加一行设置 daemon off 让 nginx 以非 daemon 方式启动)
  • 修改配置文件(配置文件通常位于/etc/supervisord.conf)后需要执行reload才能更改生效。

快速上手:你只需要几分钟

安装

1
2
3
4
pip install supervisor  # 或 uv add supervisor

# 生成配置文件到指定路径(此处路径指定为了/etc/supervisord.conf)
echo_supervisord_conf > /etc/supervisord.conf

常用命令

  • supervisord: 服务端命令:
1
2
3
4
5
# 启动服务
supervisord -c /etc/supervisord.conf

# 查看是否在运行
ps aux | grep supervisord
  • supervisorctl: 客户端命令:
1
2
3
4
5
6
supervisorctl status                         # 查看进程状态
supervisorctl start program_name # 启动program_name进程
supervisorctl stop program_name # 终止program_name进程
supervisorctl restart program_name # 重启program_name进程
supervisorctl reread # 更新配置,根据最新的配置启动所有程序
supervisorctl update # 更新配置,重启配置有变化的进程
  • supervisorctl: shell命令:
1
2
3
4
5
6
7
8
9
supervisorctl                # 进入shell命令行
> status # 查看进程状态
> start program_name # 启动program_name进程
> stop program_name # 终止program_name进程
> restart program_name # 重启program_name进程
> reread # 更新配置,根据最新的配置启动所有程序
> update # 更新配置,重启配置有变化的进程
> start fastapi:* # 启动 fastapi组 程序
> stop fastapi:* # 停止 fastapi组 程序

基础使用:

  • step1:编辑supervisor主配置文件,在配置文件的末尾加上[include]内容
1
2
3
...
[include]
files=/etc/supervisor.d/*.conf #若你本地无/etc/supervisor.d目录,请自建
  • step2:创建应用配置文件:/etc/supervisor.d/demo.conf 配置文件
1
2
3
4
5
6
7
8
9
[program:自定义的服务名称]
command=python3 /xxxx/main.py #服务的启动命令,在这里用的python环境为supervisor安装的环境,若想指定其他python环境则可指定python包的位置如command=xxxx/xxxx/bin/python3 /xxxx/main.py便可
directory=/xxxx
process_name=%(program_name)s
autorestart=true
startsecs=3
stdout_logfile=/home/task.log #输出日志文件路径
stderr_logfile=/home/task.log #报错日志文件路径
user=your_username
  • step3:启动
1
supervisord -c /etc/supervisor.conf

配置详解:磨刀不误砍柴工

打开配置文件: /etc/supervisord.conf

基础配置段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[unix_http_server]
file=/var/run/supervisor.sock ; socket文件路径
;chmod=0700 ;socket文件的mode,默认是0700
;chown=nobody:nogroup ;socket文件的owner,格式:uid:gid

[inet_http_server] ;HTTP服务器,提供web管理界面
port=0.0.0.0:9001 ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
username=user ;登录管理后台的用户名
password=pwd ;登录管理后台的密码

[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10 ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024 ;可以打开的文件描述符的最小值,默认 1024
minprocs=200 ;可以打开的进程数的最小值,默认 200

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord

[include]
files=/etc/supervisor.d/*.conf #若你本地无/etc/supervisor.d目录,请自建

程序配置段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[program:your_program_name]
command=/path/to/your/command ; 必须:要执行的命令
process_name=%(program_name)s ; 进程名
numprocs=1 ; 进程数量
directory=/path/to/run/in ; 执行命令前切换的目录
autostart=true ; 是否随supervisor启动
autorestart=unexpected ; 退出时是否自动重启
startsecs=1 ; 启动后持续运行1秒才认为是成功
startretries=3 ; 启动失败时的重试次数
user=username ; 运行用户
redirect_stderr=true ; 重定向stderr到stdout
stdout_logfile=/path/to/logfile ; stdout日志路径
stdout_logfile_maxbytes=1MB ; 日志文件最大大小
stdout_logfile_backups=10 ; 日志备份数量
environment=KEY="value" ; 环境变量

入门到进阶:让效率翻倍

Web管理界面

启动Web管理界面可以直观地监控和管理进程, 在/etc/supervisord.conf中修改[inet_http_server]的参数下列参数,修改后记得重启supervisor进程,在浏览器访问 http://<host-ip>:9001

1
2
3
4
[inet_http_server]
port=0.0.0.0:9001
username=your_username
password=your_password

进程分组管理

对于多个相关进程,可以使用分组功能进行统一管理:

1
2
3
4
5
6
7
8
9
10
11
[group:app_group]
programs=app1,app2,app3

[program:app1]
command=/path/to/app1

[program:app2]
command=/path/to/app2

[program:app3]
command=/path/to/app3

分组后可以使用下列命令进行管理整个组:

1
2
supervisorctl start app_group:
supervisorctl stop app_group:

需要注意的是:

  • 当添加了上述配置后,app1、app2和app3 的进程名就会变成 app_group:app1 、 app_group:app2和app_group:app1 ,以后就要用这个名字来管理进程了,而不是之前的 app[x]了。

Supervisor配置开机启动

方式一:

centos-7

  • 进入 / lib/systemd/system 目录,并创建 supervisord.service 文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=supervisord
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
  • 加入开机启动
1
2
systemctl enable supervisord
systemctl start supervisord

方式二

  • Linux环境中:以systemd的方式管理
    • 编写启动脚本:vim /etc/rc.d/init.d/supervisord
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/bin/sh
#
# /etc/rc.d/init.d/supervisord
#
# Supervisor is a client/server system that
# allows its users to monitor and control a
# number of processes on UNIX-like operating
# systems.
#
# chkconfig: - 64 36
# description: Supervisor Server
# processname: supervisord

# Source init functions
. /etc/rc.d/init.d/functions

prog="supervisord"

prefix="/usr"
exec_prefix="${prefix}"
prog_bin="${exec_prefix}/bin/supervisord"
PIDFILE="/var/run/$prog.pid"

start()
{
echo -n $"Starting $prog: "
daemon $prog_bin --pidfile $PIDFILE -c /etc/supervisord.conf
[ -f $PIDFILE ] && success $"$prog startup" || failure $"$prog startup"
echo
}

stop()
{
echo -n $"Shutting down $prog: "
[ -f $PIDFILE ] && killproc $prog || success $"$prog shutdown"
echo
}

case "$1" in

start)
start
;;

stop)
stop
;;

status)
status $prog
;;

restart)
stop
start
;;

*)
echo "Usage: $0 {start|stop|restart|status}"
;;

esac
  • 设置开机启动及systemd方式启动。
1
2
3
4
sudo chmod +x /etc/rc.d/init.d/supervisord
sudo chkconfig --add supervisord
sudo chkconfig supervisord on
sudo service supervisord start

实践出真知

Django应用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#项目名
[program:django]
#脚本目录
directory=/root/social_engineering/
#脚本执行命令
command=/root/anaconda3/bin/python manage.py runserver 0.0.0.0:8000 # 或用gunicorn等服务启动

#supervisor启动的时候是否随着同时启动,默认True
autostart=true
#当程序exit的时候,这个program不会自动重启,默认unexpected,设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在下面的exitcodes里面定义的
autorestart=true
#这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1
startsecs=1

#脚本运行的用户身份

#日志输出
stderr_logfile=/tmp/django_stderr.log
stdout_logfile=/tmp/django_stdout.log
#把stderr重定向到stdout,默认 false
redirect_stderr = true
#stdout日志文件大小,默认 50MB
stdout_logfile_maxbytes = 20
#stdout日志文件备份数
stdout_logfile_backups = 20

; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH
; environment=PYTHONPATH=$PYTHONPATH:/path/to/somewhere

Celery应用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#项目名
[program:celery]
#脚本目录
directory=/root/social_engineering/
#脚本执行命令
command=/root/anaconda3/bin/celery -A tasks worker --loglevel=info

#supervisor启动的时候是否随着同时启动,默认True
autostart=true
#程序崩溃时自动重启
autorestart=true
#这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1
startsecs=1

#脚本运行的用户身份

#日志输出
stderr_logfile=/tmp/celery_stderr.log
stdout_logfile=/tmp/celery_stdout.log
#把stderr重定向到stdout,默认 false
redirect_stderr = true
#stdout日志文件大小,默认 50MB
stdout_logfile_maxbytes = 20
#stdout日志文件备份数
stdout_logfile_backups = 20

Redis服务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[program:zedis]
command=/opt/zedis/redis-server /opt/zedis/redis.conf
user=redisuser
autostart=true
;启动supervisord的时候会将该配置项设置为true的所有进程自动启动
stopasgroup=true
;使用supervisorctl停止zedis时,子进程也会一起停止
killasgroup=true
;向进程组发送kill信号,包括子进程
startsecs=10
;进程从STARING状态转换到RUNNING状态所需要保持运行10s时间
startretries=3
;启动失败自动重试次数,默认是3
autorestart=true
;进程停止后自动启动
stdout_logfile=/var/log/zedis-out
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=10
stderr_logfile=/var/log/zedis-err
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=10
  • Ø 因为无法监视后台进程,需要把Zedis前台运行(daemonize no),否则会识别不到Zedis启动,重试启动3次,日志提示6379已占用。
  • Ø 因为redis.conf指定了logfile,stdout_logfile并无内容输出;如果不指定redis.conf只是启动redis-server,日志会输出到stdout_logfile。

组应用配置

  • 新建文件,fastapi_app.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[group:fastapi]
programs=fastapi-app

[program:fastapi-1]
command=/home/python/scripts/fastapi1_app.sh
directory=/home/python/fastapi-1-backend
user=python
autorestart=true
redirect_stderr=false
loglevel=info
stopsignal=KILL
stopasgroup=true
killasgroup=true

[program:fastapi-2]
command=/home/python/scripts/fastapi-2.sh
directory=/home/python/fastapi-2-backend
user=python
autorestart=true
redirect_stderr=false
loglevel=info
stopsignal=KILL
stopasgroup=true
killasgroup=true

避坑指南

问题1:sock文件不存在

问题描述unix:///tmp/supervisor.sock no such file

**根源分析:**在supervisor默认配置中,其启动的sock等都会放到tmp目录,而tmp目录会自动清理导致无法使用supervisorctl

解决方案

1
2
3
4
5
6
7
8
9
# 修改主配置文件中的tmp路径
sed -i 's|/tmp/supervisor|/var/run/supervisor|g' /etc/supervisord.conf

# 创建所需目录并设置权限
mkdir -p /var/run/supervisor
chmod 755 /var/run/supervisor

# 重启supervisor
supervisorctl reload

问题2:进程不断重启

问题描述:进程启动后Supervisor不断尝试重启

解决方案

  • 确保管理的进程以前台方式运行
  • 检查进程启动命令是否正确
  • 查看日志文件定位具体问题

问题3:启动了多个supervisord服务,导致无法正常关闭服务

问题描述:在运行supervisord -c /etc/supervisord.conf之前,直接运行过``supervisord -c /etc/supervisord.d/xx.conf`导致有些进程被多个superviord管理,无法正常关闭进程

解决方案

  • 使用ps -fe | grep supervisord查看所有启动过的supervisord服务,kill相关的进程。

总结一下

Supervisor是一款强大且灵活的进程管理工具,合理配置显著提升服务的稳定性和可维护性。本文从安装配置、基础使用到进阶使用全面介绍了Supervisor的使用方法, 希望能帮助你在实际工作中更好地运用这一工具。

最佳实践建议:

  • 为每个服务创建独立的配置文件
  • 合理配置日志轮转,避免磁盘空间不足
  • 使用Web界面进行日常监控和管理
  • 设置进程分组,简化管理操作
  • 配置开机启动,确保服务可靠性

本站由 BluesSen 使用 Stellar 1.33.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站总访问量