语言教育项目实战之二:Python管理多并发Web服务
背景
基于#python# Python的 Flask写了一个WEB服务,可以用来将文本转为语音。现在要发布到生产环境,需要启动多个进程并行服务,并再故障后能够自动恢复。初步考虑使用Gunicorn和Supervisor来管理此Web服务。在此之前找LLM 们咨询下,确定可行性和先进性。
大体而言,方案在中小规模服务上可行,后期可结合nginx做负载均衡,以及用celery进行异步任务会更加高效。下面介绍使用Gunicorn和#supervisor#管理服务进程。
Gunicorn
# 安装
pip install gunicorn
# 支持异步
pip install gevent
# 命令行运行flask web服务
gunicorn -w 4 -k gevent -b 0.0.0.0:8000 \
--timeout 120 \ # 超时时间(处理长语音)
--access-logfile /var/log/gunicorn/access.log \
--error-logfile /var/log/gunicorn/error.log \
app:app
# 也可以写一个配置文件,然后通过-c参数指定启动
gunicorn -c gunicorn.conf.py app:app
# 调试完毕后,可以让其后台运行
gunicorn -c gunicorn.conf.py app:app --daemon
配置文件内容如下:
# 绑定的IP和端口
bind = "127.0.0.1:5000"
# 工作进程数
workers = 1
# 每个工作进程的线程数
threads = 2
# 工作模式,默认为sync同步模式
worker_class = "sync"
# 日志级别
loglevel = "info"
# 日志文件路径
accesslog = "log/access.log"
errorlog = "log/error.log"
# 设置超时时间
timeout = 60
# 设置最大请求数
max_requests = 1000
# 设置每个工作进程的最大请求数
max_requests_jitter = 50
# 设置是否守护进程模式
daemon = False
# 设置pid文件路径
pidfile = "tmp/gunicorn.pid"
手动启动、停止gunicorn服务,需要结合启动的flask服务名。如下,编制一个sh脚本:
#!/usr/bin/bash
# 用gunicorn启动本项目服务,项目默认运行在项目根目录下,引用包应该以此为运行目录
DIR="${HOME}/code/pywebsvr"
# 检查python环境,虚拟环境是否已经创建,如果没有需要创建
init_python_env(){
echo "INIT *** venv *** "
if [ -d "${DIR}/venv" ]; then
echo "python venv has been initted."
else
cd $DIR;
python3 -m venv venv ;
fi
}
# 停止服务
stop_flask_service(){
echo "STOP *** $SVR *** , the running processes : " $@
for pid in $@
do
echo "Killing process with PID : $pid"
kill -9 $pid
sleep 3
done
}
# 启动服务
start_flask_service(){
echo "START *** $SVR ***"
cd $DIR
init_python_env
source venv/bin/activate ;
# pip install -r requirements.txt;
gunicorn -c dat/gunicorn_config.py $SVR --daemon
}
# 检查服务是否已经启动,如果没有,启动服务;如果有,则退出
check_flask_service_and_start(){
echo "$ CHECK ***$SVR in $DIR running *** "
flask_pid=$(pgrep -f "$SVR"|grep -v $)
if [ -z "$flask_pid" ]; then
echo -e "*** $SVR *** is not running."
start_flask_service
else
echo -e "*** $SVR *** is running."
fi
}
# 检查服务是否已经启动,如果没有,启动服务;如果有,则重启服务
check_flask_service_and_restart(){
echo "$ CHECK ***$SVR running *** "
flask_pid=$(pgrep -f "$SVR" |grep -v $)
if [ -z "$flask_pid" ]; then
echo -e "*** $SVR *** is not running."
start_flask_service
else
echo -e "*** $SVR *** is running."
stop_flask_service $flask_pid
start_flask_service
fi
}
# 检查服务是否已经启动,如果没有,什么都不做;如果有,则停止服务
check_flask_service_and_stop(){
echo "$ CHECK ***$SVR running *** "
flask_pid=$(pgrep -f "$SVR"|grep -v $)
if [ -z "$flask_pid" ]; then
echo -e "*** $SVR *** is not running."
else
echo -e "*** $SVR *** is running."
stop_flask_service $flask_pid
fi
}
然后编写start,stop,restart脚本
## start.sh
#!/usr/bin/bash
#此脚本负责启动falsk服务。 可将实际的服务路径目录,和服务名修改即可;
SVR="src.main:app"
# !!! 不用修改下面的代码
script_path=$(dirname "$(readlink -f "$0")")
cd $script_path; source ./function_v2.sh ;
check_flask_service_and_start
## stop.sh
#!/usr/bin/bash
#此脚本负责启动falsk服务。 可将实际的服务路径目录,和服务名修改即可;
SVR="src.main:app"
#SVR="demo.gql_crud_users:app"
# !!! 不用修改下面的代码
script_path=$(dirname "$(readlink -f "$0")")
cd $script_path; source ./function_v2.sh ;
check_flask_service_and_stop
Supervisor
安装supervisor,#supervisor#可以用来管理各种服务和命令行程序。
# 安装
sudo apt-get install supervisor
编写配置文件,可参考下面的关键部分
[program:flask_app]
command=/home/release/bin/gunicorn -c /path/to/gunicorn.conf.py app:app
directory=/home/release/app
user=www-data # 运行用户
autostart=true # 系统启动时自动启动
autorestart=true # 崩溃后自动重启
stderr_logfile=/var/log/flask_app.err.log
stdout_logfile=/var/log/flask_app.out.log
加载配置、启动、停止、查看状态
# 加载配置
sudo supervisorctl reread
sudo supervisorctl update
# 启动服务
sudo supervisorctl start flask_app
# 查看状态
sudo supervisorctl status flask_app