supervisor管理进程,是通过fork/exec的方式将这些被管理的进程当作supervisor的子进程来启动,所以我们只需要将要管理进程的可执行文件的路径添加到supervisor的配置文件中就好了。此时被管理进程被视为supervisor的子进程,若该子进程异常中断,则父进程可以准确的获取子进程异常中断的信息,可以选择是否自己启动和报警。通过在配置文件中设置autostart=true,可以实现对异常中断的子进程的自动重启。基于Python语言开发,比如rabbitmq消费程序需要配合supervisor实现常驻进程
#!/bin/bash
#开启消费进程
supervisorctl start bill_orders:
#检测消费进程并开启生产者
procNumber=`ps -ef |grep -w "/var/www/project/bin/console consumer:rebill"|grep -v grep|wc -l`
if [ $procNumber -le 0 ];then
echo 'supervisorctl 启动rabbitmq消费进程失败!'
else
php /var/www/project/bin/console more:win:to:mq --ex_name=orders.call --route_key=zx.cdr --mq_config=rabbitmq
fi
#todo 检查消费完毕
#消费完毕后,关闭消费者
supervisorctl stop bill_orders:
安装supervisor
#检查是否已经安装
supervisord --version
#安装pip
yum install -y epel-release
yum install -y python-pip
#pip安装supervisor
pip install supervisor
在末尾加入
echo 'export PATH="/usr/local/bin:$PATH"' >> /etc/profile
保存修改后,使用source命令重新加载配置文件:
source /etc/profile
配置Supervisor
#创建supervisor所需目录
mkdir /etc/supervisor
mkdir /etc/supervisor/supervisord.d
#创建supervisor配置文件
echo_supervisord_conf > /etc/supervisor/supervisord.conf
默认地已经有/etc/supervisor/supervisord.conf这么个配置文件。并且最后的自定义配置文件已经包括了。去掉;
[include]
files = supervisord.d/*.ini
file=/tmp/supervisor.sock 改成 file=/var/run/supervisor.sock
serverurl=unix:///tmp/supervisor.sock 改成 serverurl=unix:///var/run/supervisor.sock,
logfile=/tmp/supervisord.log 改成 logfile=/var/log/supervisor.log
pidfile=/tmp/supervisord.pid 改成 pidfile=/var/run/supervisor.pid
创建文件目录并授权
sudo chmod 777 /var/log
sudo touch /var/run/supervisor.sock
sudo chmod 777 /var/run/supervisor.sock
常用应用让supervisor来管理它,放在/etc/supervisor/supervisord.d/目录下,以.ini作为扩展名
vim /etc/supervisor/supervisord.d/nginx.ini
[program:nginx]
command = /usr/sbin/nginx -g 'daemon off;'
startsecs=0
autostart=true
autorestart=true
stdout_logfile=/var/log/nginx_sup.log
stopasgroup=true
killasgroup=true
vim /etc/supervisor/supervisord.d/elasticsearch.ini
[program:elasticsearch]
command = su - elasticsearch -c "/data/product/service/elasticsearch-5.4.2/bin/elasticsearch -d"
autostart = true
autorestart = true
stopwaitsecs=1
startsecs=1
user=elasticsearch
stopasgroup = true
stdout_logfile = /var/log/elasticsearch.log
stderr_logfile = /var/log/redis/elasticsearcherr.log
vim /etc/supervisor/supervisord.d/kafka.ini
[program:kafka]
command=/data/product/service/kafka_2.11-0.8.2.2/bin/kafka-server-start.sh /data/product/service/kafka_2.11-0.8.2.2/config/server.properties
autostart=true
autorestart=true
stopwaitsecs=1
stopasgroup=true
startsecs=50
user=root
stderr_logfile=/var/log/kafkaerr.log
stdout_logfile=/var/log/kafka.log
vim /etc/supervisor/supervisord.d/mysql.ini
[program:mysql]
command=/usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock
autorestart=unexpected
stopwaitsecs=1
stopasgroup=true
user=mysql
stderr_logfile=/tmp/err.log
std_logfile=/tmp/out.log
vim /etc/supervisor/supervisord.d/redis.ini
[program:redis]
command=/usr/bin/redis-server
autostart=true
autorestart=true
stopwaitsecs=1
startsecs=3
user=root
stopasgroup=true
stdout_logfile=/var/log/redis/redis.log
stderr_logfile=/var/log/redis/redis.log
vim /etc/supervisor/supervisord.d/zookeeper.ini
[program:zookeeper]
command=/data/product/service/zookeeper-3.4.10/bin/zkServer.sh start-foreground zoo-1.cfg
autorestart=unexpected
stopwaitsecs=1
stopasgroup=true
stderr_logfile=/var/log/zookeeper.log
std_logfile=/var/log/zookeepererr.log
给自己需要的脚本程序编写一个子进程配置文件
#rabbitmq 10个常驻内存消费者
[program:consumer_cdr]
command=php /data/www/bin/console app:consumer-mq-queue
process_name=%(program_name)s_%(process_num)02d ; 多进程名称肯定不同,匹配多个 (default %(program_name)s)
numprocs=10 ; 启动几个进程 (def 1)
autostart=true ; 随着supervisord的启动而启动 (default: true)
autorestart=unexpected ; 自动重启。 (default: unexpected)
startsecs=1 ; 这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了(def. 1)
startretries=3 ; 启动失败时的最多重试次数 (default 3)
[group:consumercdr]
programs=consumer_cdr
priority=999 ;数字越高,优先级越高
supervisorctl命令
Supervisor 是一个 C/S 模型的程序,supervisord
是 server 端,supervisorctl
是 client 端。Supervisor 同时还提供了另外一种进程组的管理方式,通过这种方式,可以使用 supervisorctl 命令来管理一组进程
基本命令(-C 可省略)
supervisord -c /etc/supervisor/supervisord.conf 通过配置文件启动supervisor
sudo supervisorctl status 查看状态
supervisorctl -c /etc/supervisor/supervisord.conf reload 重新载入配置文件
supervisorctl start [all]|[x] 启动所有/指定的程序进程
supervisorctl stop [all]|[x] 关闭所有/指定的程序进程
重启服务:载入最新的配置文件并启动所有进程(新+老)
supervisorctl reload
更新新的配置到supervisord,不改变supervisorctl原有的进程状态,新加入的配置文件进程开启
supervisorctl update
配置
[group:thegroupname]
programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions
priority=999 ; 数字越高,优先级越高(default 999)
启动/关闭
以后执行 supervisorctl stop thegroupname: 就能同时结束 progname1 和 progname2,执行 supervisorctl stop thegroupname:progname1 就能结束 progname1。
supervisorctl stop thegroupname:
supervisorctl start zhoujy
开启web界面操作
[inet_http_server] ; inet (TCP) server disabled by default
port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
username=user ; (default is no username (open server))
password=123 ; (default is no password (open server))
通过http://localhost:9001访问如下图
运行状态,RUNNING
表示运行中 FATAL
表示运行失败 STARTING
表示正在启动 STOPED
表示任务已停止
1、日志权限错误
IOError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
原因,/var/log/supervisor/supervisord.log没有写权限,赋予权限即可:
sudo chmod -R 777 /var/log/supervisor/supervisord.log
2、开启HTTP Server错误
Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)
配置文件中 /var/run 文件夹,没有授予启动 supervisord 的相应用户的写权限。/var/run 文件夹实际上是链接到 /run,因此我们修改 /run 的权限。
sudo chmod 777 /run
一般情况下,我们可以用 root 用户启动 supervisord 进程,然后在其所管理的进程中,再具体指定需要以那个用户启动这些进程。3、日志权限问题
'INFO spawnerr: unknown error making dispatchers for 'app_name': EACCES'
修改日志文件的权限
sudo chmod 777 /usr/log/supervisor/youAppName.log
启动某应用的时候,发现supervisord会报错「spawn error」,开始以为是进程问题
supervisor: couldn't setuid to 0: Can't drop privilege as nonroot user
supervisor: child process was not spawned
所以,将配置文件/etc/supervisor/supervisord.conf 的user改为root
[supervisord]
user=root
如果不安装Supervisor,可以借助Linux系统crontab实现类似功能bash monitor.sh rabbitmq-server
#!/bin/sh
process_name=$1
#process_name=$(echo $process_path | awk -F / '{print $NF}')
script_name=monitor.sh
check_process()
{
process_exists=$(ps -ef | grep $process_name | grep -v grep|grep -v $script_name | wc -l)
echo "进程数量:" $process_exists
if [ $process_exists -eq 0 ];then
return 0
else
return 1
fi
}
startMonitor()
{
check_process
if [ $? -eq 0 ]; then
echo "进程未启动,现在开始启动!"
#sudo systemctl start $process_name #centos
sudo service $process_name start #ubuntu
else
echo "进程已经启动"
fi
}
startMonitor