概述

研发人员交付测试和上线产品时,需要对服务和产品以后台进程的方式启动。所以便利的后台进程工具可以很好的帮助你管理你的进程。确切的说:成为系统的守护进程(daemon)。

任务

我们一般通过如下方式的命令运行的大多数是前台任务,:

1
2
3
4
#python task
python main.py
#nodejs task
nodejs main.js

前台任务有很大的限制。我们无法获得标准输入stdin(它独占窗口session),当前的session中断和退出,会立即中断任务。如果想结束改task只能等待完成或者手动结束。我们更倾向于后台任务,通过如下方式:

1
2
3
4
#python task
python main.py &
#nodejs task
nodejs main.js &

这样就会把当前进程置为后台进程。如果想让前台任务变为后台任务,可以先通过CTRL+Z再执行,bg命令。快捷键说明:

CTRL+C是强制中断程序的执行,,进程已经终止。 CTRL+Z将任务暂停或者挂起,此任务并没有结束,它仍然在进程中。只是维持挂起的状态,用户可以使用fg/bg操作继续前台或后台的任务,fg命令重新启动前台被中断的任务,bg命令把被中断的任务放在后台执行。 CTRL+D 发送一个特殊的二进制值,表示 EOF。 后天任务继承当前session的stdoutstderr。后台任务和前台任务的这种主要通过SIGHUB信号来处理和判断的,SIGHUB都有固定的标识和意义。 1.用户创建session,会向OS发送一个SIGHUP信号表示我可以调用操作系统的资源和进程。 2.用户退出session,通过系统调用发送给OS SIGHUP信号,OS将SIGHUP信号发送给session开启的所有进程和子进程,当收到退出SIGHUB指令后会回收资源并自动退出。由于前台任务是独占窗口session,所以当session退出时前台任务会收到SIGHUP信号并退出。后台任务主要通过huponexit参数来决定后台任务是否收到SIGHUB命令。该参数默认为off,所以后台任务默认是不会接收到SIGHUB信号的。

1
2
vm@vm:~$ shopt | grep huponexit
huponexit      	off

如果启用了该参数,那么我们的后台任务也会退出。所以我们如果想写出稳定的后台服务,应该是避免SIGHUB信号。

后台任务工具

nohup、disown、screen、supervisor和Systemd等工具都可以避免SIGHUB信号,首推Systemd,但是备受争议它为违背了"keep simple, keep stupid"Unix哲学,其次supervisor和screen。

screen

1
2
3
4
5
6
# 创建screen并制定名字
$ screen -S name
# 切回指定 session
$ screen -r name or pid_number
# 列出所有 session
$ screen -ls

创建完screen后,在新的session书写自己的后台服务即可,书写完成之后通过CTRL+a,d 来退出当前会话。

supervisor

supervisor是一个后台进程管理工具,方便管理进程的工具。最主要有下面两个功能: 1)将非daemon程序变成deamon方式运行,对于daemon程序则不能监控。比如你通过python自己写的一个daemon服务是无法监控的。 2)对程序进行监控,当程序退出时,可以自动拉起程序。

1
pip install supervisor

如果你监控多个daemon时可通过定制化进程conf来配置,可以创建一个confs的文件夹,把每个daemon的进程的服务放到改文件夹下,最后在supervisor的默认conf文件中包含该所有的配置文件即可。如果只是单个daemon,可以直接使用默认conf中。

1
2
3
4
5
6
7
8
#第一种,创建confs
mkdir -m 755 -p /etc/supervisor/conf.d/
emacs /etc/supervisor/supervisord.conf
#找到如下节点进行配置
[include]
files = /etc/supervisor/conf.d/*.conf
#第二种,直接采用默认conf
echo_supervisord_conf > /etc/supervisor/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
[program:test]
command = /usr/bin/test
#启动程序的命令;
autostart = true
#在supervisord启动的时候也自动启动;
autorestart = true
#程序异常退出后自动重启;
startsecs = 5
#启动5秒后没有异常退出,就当作已经正常启动了;
startretries = 3
#启动失败自动重试次数,默认是3;
#user = nobody
#开启进程使用哪个用户和组启动(这里memcached启动时指定了nobody用户所以就不用再指定了);
redirect_stderr = true
#把stderr重定向到stdout,默认false;
stdout_logfile=/var/log/out-memcache.log
#标准日志输出;
stderr_logfile=/var/log/err-memcache.log
#错误日志输出;
stdout_logfile_maxbytes = 20MB
#标准日志文件大小,默认50MB;
stdout_logfile_backups = 20
#标准日志文件备份数;  

process_name=%(process_num)s
numprocs=3 

最后启动生效并测试是否成功启动:

1
2
supervisord -c /etc/supervisor/supervisord.conf
ps -ef | grep supervisor | grep -v grep

supervisor使用

 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
1.查询各进程运行状态
supervisorctl status
2.启、停、重启业务进程,test为进程名,即[program:test]里配置的值
supervisorctl start test
supervisorctl stop test
supervisorctl restart test
3.重启所有属于名为groupworker这个分组的进程
supervisorctl start groupworker
supervisorctl stop groupworker
supervisorctl restart groupworker
4.启、停、重启全部进程(不会载入最新的配置文件)
supervisorctl start all
supervisorctl stop all
supervisorctl restart all
5.重新加载配置文件,停止原有进程并按新的配置启动所有进程(注意:所有进程会停止并重启,线上操作慎重)
supervisorctl reload
6.根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而被重启(注意:这才是线上可以操作的命令,不会重启原有进程)
supervisorctl update
注意:显示状态为stop停止掉的进程,用reload或者update都不会自动重启。
交互式
[root@aaa ]# supervisorctl
memcached                       RUNNING   pid 1234, uptime 0:01:47
supervisor> stop test
memcached: stopped
supervisor> start test
memcached: started
supervisor> status
memcached                       RUNNING   pid 1234, uptime 0:00:04
supervisor> restart test
memcached: stopped
memcached: started
supervisor> status
memcached                       RUNNING   pid 1234, uptime 0:00:02
supervisor>

Systemd

关于Systemd,即可网上有一个非常详细的教程,大家可以search一下。