使用Systemd管理Swoole服务

Systemd 是 Linux 系统工具,用来启动守护进程。

Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。包括:systemctl,systemd-analyze,hostnamectl,localectl,timedatectl,loginctl

更多参考:Systemd介绍

所以Swoole的服务器程序可以编写一段service脚本,交由systemd进行管理。实现故障重启、开机自启动等功能。

使用systemd管理swoole服务参考文档:swoole官方文档

Demo:

在/etc/systemd/system/swoole_http.service新建一个service文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Swoole Http service
After=network.target
After=syslog.target
[Service]
Type=forking
PIDFile=/home/www/http/bin/server.pid
ExecStart=/home/www/http/bin/server
ExecStop=/bin/kill -15 $MAINPID
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target graphical.target

需要注意的是$MAINPID必须要是manager的id,不然启动或者重启的时候会报错。而且还需要修改swoole配置参数,把swoole的守护进程化设置为daemonize => 1。

kill -USR1 pid 重启woker进程和task进程

kill -USR2 pid 重启task进程

kill -15 管理进程id 关掉所有的manager相关进程

关于swoole重启的文档:链接

使用Supervisor管理swoole服务

Supervisor是一个客户/服务器系统,它可以在类Unix系统中管理控制大量进程。Supervisor使用python开发,有多年历史,目前很多生产环境下的服务器都在使用Supervisor,部署python程序经常这个。

Supervisor的服务器端称为supervisord,主要负责在启动自身时启动管理的子进程,响应客户端的命令,重启崩溃或退出的子进程,记录子进程stdout和stderr输出,生成和处理子进程生命周期中的事件。可以在一个配置文件中配置相关参数,包括Supervisord自身的状态,其管理的各个子进程的相关属性。配置文件一般位于/etc/supervisord.conf。

Supervisor的客户端称为supervisorctl,它提供了一个类shell的接口(即命令行)来使用supervisord服务端提供的功能。通过supervisorctl,用户可以连接到supervisord服务器进程,获得服务器进程控制的子进程的状态,启动和停止子进程,获得正在运行的进程列表。客户端通过Unix域套接字或者TCP套接字与服务端进行通信,服务器端具有身份凭证认证机制,可以有效提升安全性。当客户端和服务器位于同一台机器上时,客户端与服务器共用同一个配置文件/etc/supervisord.conf,通过不同标签来区分两者的配置。

Supervisor也提供了一个web页面来查看和管理进程状态,这个功能非常酷.

安装Supervisor

1
2
3
4
5
6
# 我们可以通过pypi安装
pip install supervisor
# 或者从pypi上下载源码,然后安装
python setup.py install
# 安装完之后,使用下列命令来生成配置文件
echo_supervisord_conf > /etc/supervisord.conf
1
# mkdir /etc/supervisord.d 用户存放被监控进程的配置文件

修改/etc/supervisord.conf配置文件:

1
2
3
4
在文件结尾[include]节点处把
;files = relative/directory/*.ini改为files =/etc/supervisord.d/*.conf
同时还需要去掉[include]前面的;

保存并退出。

把supervisor加入开机自启动服务

到systemd系统下新建一个service配置文件

1
vim /lib/systemd/system/supervisor.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=supervisor
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/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 graphical.target

上述文件编写后,执行如下命令即可:

1
systemctl enable supervisor.service

加入开机自启动服务

1
systemctl daemon-reload

重新载入systemd,扫描新的或有变动的单元。

实际上supervisor已经加入了systemctl管理了,后续起停supervisor服务都可以通过systemctl来控制了。

1
2
3
4
5
6
7
8
9
systemctl start supervisor.service 启动服务
systemctl stop supervisor.service 停止服务
systemctl restart supervisor.service 重新启动服务
systemctl reload supervisor.service 重载配置文件
systemctl status supervisor.service 查看服务状态

在/etc/supervisord.d 增加一个程序的demo配置参数:

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
[program:cat] ;程序名
command=/bin/cat ;命令绝对路径,可以包含参数
process_name=%(program_name)s ;进程名
numprocs=1 ;supervisor启动多少个该程序,如果大于1,那么进程名必须包括%(process_num)s
directory=/tmp ;该进程的启动时的工作目录
umask=022 ;掩码
priority=999 ;优先级
autostart=true ;该程序是否在supervisor启动时启动
autorestart=true ;如果为false,那么该程序的相关进程永远不会自动重启。如果为unexpected,该程序的相关进程仅会在退出码为exitcodes中的值时重启;如果为true时
startsecs=10 ;最大启动时间
startretries=3 ;最大启动重试次数。超过这个次数后,该进程会标记为FATAL状态
exitcodes=0,2 ;退出码,关联autorestart=unexpected
stopsignal=TERM ;关闭该程序相关进程所发送的信号量。可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2
stopwaitsecs=10 ;supervisord父进程等待该程序的相关子进程返回SIGCLILD信号量的时间,超时后则发送SIGKILL
user=chrism ;启动该程序进程的用户
redirect_stderr=false ;如果为true,则将该程序的进程错误输出到supervisor主日志文件中
stdout_logfile=/tmp ;标准输出
stdout_logfile_maxbytes=1MB ;日志轮滚
stdout_logfile_backups=10 ;日志轮滚
stdout_capture_maxbytes=1MB
stderr_logfile=/a/path
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=10
stderr_capture_maxbytes=1MB
environment=A="1",B="2" ;!环境变量信息
serverurl=AUTO ;传送给该子进程的环境变量SUPERVISOR_SERVER_URL ,AUTO则自动提供一个Supervisord的URL。用于该进程可以和内部HTTP Server进行通信,简化进程管理。

从swoole的文档我们得知:
Swoole提供了柔性终止/重启的机制,管理员只需要向SwooleServer发送特定的信号,Server的worker进程可以安全的结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SIGTERM: 向主进程/管理进程发送此信号服务器将安全终止
在PHP代码中可以调用$serv->shutdown()完成此操作
SIGUSR1: 向主进程/管理进程发送SIGUSR1信号,将平稳地restart所有worker进程
在PHP代码中可以调用$serv->reload()完成此操作
swoole的reload有保护机制,当一次reload正在进行时,收到新的重启信号会丢弃
如果设置了user/group,Worker进程可能没有权限向master进程发送信息,这种情况下必须使用root账户,在shell中执行kill指令进行重启
reload指令对addProcess添加的用户进程无效
#重启所有worker进程
kill -USR1 主进程PID
#仅重启task进程
kill -USR2 主进程PID

supervisor的程序restart的原理是实际上是发信号,所以我们需要给swoole的程序stop信号配置为:stopsignal=TERM

同时还需要把swoole的守护进程化设置为daemonize => 0,不然会报spawned error

supervisorctl控制program

现在supervisor的server端我们已经交给systemd去管理,现在我们可以通过supervisorctl去控制配置添加的program

1
2
3
4
5
6
7
supervisorctl -c supervisor.conf status 察看supervisor的状态
supervisorctl -c supervisor.conf reload 重新载入 配置文件
supervisorctl -c supervisor.conf start [all]|[appname] 启动指定/所有supervisor管理的程序进程
supervisorctl -c supervisor.conf stop [all]|[appname] 关闭指定/所有 supervisor管理的程序进程