作为一个Python选手,工作中需要的一些服务接口一般会用Flask来开发。

Flask非常容易上手,它自带的app.run(host="0.0.0.0", port=7001)用来调试非常方便,但是用于生产环境无论是处理高并发还是鲁棒性都有所欠缺,一般会配合WGSI容器来进行[生产环境的部署][1]。

小磊哥推荐了参考文章[1]中的部署方式,希望将已有的服务放到gunicorn或者Tornado中部署,并用supervisor来管理所有进程(有几个不同的服务)。

经过调研和尝试

  1. gunicorn可以结合gevent来进行部署,因此在高并发场景下也可适用,于是决定采用gunicorn进行部署。
  2. gunicorn和supervisor会有一定的冲突,即使gunicorn中没有设置为后台启动,supervisor也只会管理gunicorn的master进程;
  3. supervisor的重启服务对于无响应的Flask进程来说并不生效,不能很好地解决我的服务由于某些原因无法正常响应但又找不到方法解决的问题,因此暂时决定不用supervisor。

环境安装

首先pip安装gunicorn。
pip install gunicorn --user

Tips. pip --user用法

由于是部署在公司云主机上,通常不会给root权限。之前都是提工单给SA sudo装的,后来发现更安全也更方便的方法是pip install xxx --user,美中不足是安装完以后需要手动添加PATH
export PATH=/home/username/.local/bin:$PATH
方便起见可以加到~/.bash_profile

gunicorn 命令启动

简单地,gunicorn可以通过gunicorn -w 4 -b 127.0.0.1:4000 run:app启动一个Flask应用。其中,

  • -w 4是指预定义的工作进程数为4,
  • -b 127.0.0.1:4000指绑定地址和端口
  • run是flask的启动python文件,app则是flask应用程序实例

其中run.py中文件的可能形式是:

# run.py
from flask import Flask
app = Flask(__name__)

通过gunicorn -h可以看到gunicorn有非常多的配置项,因此通常会写成一个config.py文件来进行配置。看了一下文档似乎没有给出正确的config.py中配置项的命名,并且有些博客博主给出的配置项命名是错误的,导致配置没有生效,踩了不少的坑(我找不到那篇坑坑的文章了)。这篇博客[2]给出了一些比较常用且正确的配置。

我所用项目的配置项如下:

# config.py
import os
import gevent.monkey
gevent.monkey.patch_all()import multiprocessing # debug = True loglevel = 'debug' bind = "0.0.0.0:7001" pidfile = "log/gunicorn.pid" accesslog = "log/access.log" errorlog = "log/debug.log" daemon = True # 启动的进程数 workers = multiprocessing.cpu_count() worker_class = 'gevent' x_forwarded_for_header = 'X-FORWARDED-FOR' 
1. debug = True

生产环境不需要这个配置项,但调试的时候还是挺好用的。而且,开启debug项后,在启动gunicorn的时候可以看到所有可配置项的配置,如下所示。
之前在被上一篇博主欺骗的时候,仔细看了调试信息,发现accesslog和errorlog都没有被配置,所以导致启动以后看不到任何日志。

config.py中只需要配置需要修改的项的,大部分采用默认配置即可。默认配置的具体配置内容可以通过gunicorn -h来查询。

*配置文件和调试信息来自两个不同进程,因此信息可能有细微差异

# Debug Info[2018-01-18 17:38:47 +0000] [16015] [DEBUG] Current configuration: proxy_protocol: False worker_connections: 1000 statsd_host: None max_requests_jitter: 0 post_fork: <function post_fork at 0x21037d0> errorlog: - enable_stdio_inheritance: False worker_class: gunicorn.workers.ggevent.GeventWorker ssl_version: 2 suppress_ragged_eofs: True syslog: False syslog_facility: user when_ready: <function when_ready at 0x2103500> pre_fork: <function pre_fork at 0x2103668> cert_reqs: 0 preload_app: False keepalive: 2 accesslog: log/debug.log group: 1001 graceful_timeout: 30 do_handshake_on_connect: False spew: False workers: 2 proc_name: None sendfile: None pidfile: log/gunicorn.pid umask: 0 on_reload: <function on_reload at 0x2103398> pre_exec: <function pre_exec at 0x2103d70> worker_tmp_dir: None limit_request_fields: 100 pythonpath: None on_exit: <function on_exit at 0x21065f0> config: gunicorn_conf.py logconfig: None check_config: False statsd_prefix: secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'} reload_engine: auto proxy_allow_ips: ['127.0.0.1'] pre_request: <function pre_request at 0x2103ed8> post_request: <function post_request at 0x2106050> forwarded_allow_ips: ['127.0.0.1'] worker_int: <function worker_int at 0x2103aa0> raw_paste_global_conf: [] threads: 1 max_requests: 0 chdir: /home/hzyangxiao2014/POPORobot/QASP daemon: False user: 1028 limit_request_line: 4094 access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" certfile: None on_starting: <function on_starting at 0x2103230> post_worker_init: <function post_worker_init at 0x2103938> child_exit: <function child_exit at 0x21061b8> worker_exit: <function worker_exit at 0x2106320> paste: None default_proc_name: run:app syslog_addr: udp://localhost:514 syslog_prefix: None ciphers: TLSv1 worker_abort: <function worker_abort at 0x2103c08> loglevel: debug bind: ['0.0.0.0:7001'] raw_env: [] initgroups: False capture_output: False reload: False limit_request_field_size: 8190 nworkers_changed: <function nworkers_changed at 0x2106488> timeout: 30 keyfile: None ca_certs: None tmp_upload_dir: None backlog: 2048 logger_class: gunicorn.glogging.Logger 
2. 日志
# config.py
accesslog = "log/access.log"
errorlog = "log/debug.log"
loglevel = "debug"
  • 需要log目录存在。如果不存在,启动会报错
  • accesslog是访问日志,可以通过access_log_format设置访问日志格式。详细的方法可以见参考文章[2]
  • loglevel用于控制errorlog的信息级别,可以设置为debug、info、warning、error、critical。
3. workers

worker_class是指开启的每个工作进程的模式类型,默认为sync模式,也可使用gevent模式。

workers是工作进程数量,在上述config.py中,取的是CPU的数量。需要注意部署机器的性能,不能无限制多开。多篇文章中推荐了multiprocessing.cpu_count() * 2 + 1这个数量,考虑到我会在一个机器上部署两个服务,因此数量减半。

4. daemon

daemon = True意味着开启后台运行,默认为False

总结

gunicorn的环境配置和使用都比较简单,也解决了我总是用nohup python run.py >out.log 2>&1 &来启动Flask后台服务的问题。

在采用gunicorn部署之前,我也对后台服务的目录结构进行了调整。虽然只是便利工作的服务,也希望可以尽可能变的更加professional~

转载于:https://www.cnblogs.com/ExMan/p/10073301.html

gunicorn部署Flask服务相关推荐

  1. 利用flask写的接口(base64, 二进制, 上传视频流)+异步+gunicorn部署Flask服务+多gpu卡部署

    一.flask写的接口 1.1 manage.py启动服务(发送图片base64版) 这里要注意的是用docker的话,记得端口映射 #coding:utf-8 import base64 impor ...

  2. 使用 Nginx + Gunicorn 部署 Flask 项目

    使用 Nginx + Gunicorn 部署 Flask 项目 Flask Web 项目开发完成后,开发人员只是在开发环境运行,只有本地可以访问到项目.如果要让用户访问到项目,需要将项目部署到生产环境 ...

  3. Gunicorn部署Flask

    Gunicorn是一个被广泛使用的高性能的Python WSGI UNIX HTTP服务组件(WSGI: Web Server Gateway Interface),移植自Ruby的独角兽(Unico ...

  4. pip安装gunicorn_gunicorn部署Flask服务

    作为一个Python选手,工作中需要的一些服务接口一般会用Flask来开发. Flask非常容易上手,它自带的app.run(host="0.0.0.0", port=7001)用 ...

  5. Flask+gunicorn部署HTTP服务

    FLASK Flask提供了HTTP开发服务的框架,但是他本身不提供HTTP Server.内部集成的一个简单的Server只是用于开发调试. Flask内部的HTTP服务只用于开发使用,在启动Fla ...

  6. 使用 gunicorn 部署flask项目

    1.WSGI协议 Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求.Web框架和Web服务器之间的通信,需要一套双方都遵守的接口协议.WSGI协议就是用来统一这两者的接口 ...

  7. PyTorch+Flask+Gunicorn 部署深度模型服务

    目录 简介 项目实现 模型实现 部署Flask服务 Gunicorn加速 性能测试 Python 多线程+requests ab工具 (可选)HTML网页端 总结 参考文献 简介 初入职场,对于训练完 ...

  8. flask+gunicorn部署

    1.flask flask实际上就是用来作为python部署服务的框架,方便别人调用你写的服务.本文主要记载下自己的使用过程 1.1.flask安装 pip install flask 1.2.fla ...

  9. 腾讯云Unubtu 16.04 (gunicorn+supervisor+ngnix+mongodb)部署Flask应用

    1.申请腾讯云服务 我申请了免费使用的云服务器 ,选择安装的Linux版本是ubuntu16.04.1 LTSx86_64.我个人PC安装使用的也是这个版本,比较熟悉些. 详细参考帮助文档. 2.登录 ...

最新文章

  1. 基础IPsec-remote基本配置
  2. 各种字符串分拆处理函数.sql
  3. ALVのイベントを取得する方法
  4. vue 表单 input text
  5. 字符串常量强制转换为字符指针
  6. bzoj 4827 礼物
  7. 游戏环境检测工具_自带基准测试的游戏大作盘点
  8. XSS跨站点脚本攻击解决方案
  9. 如何用MFC做漂亮的界面
  10. js获取ip地址的私有地址 或者公有地址
  11. 峰值信噪比和结构相似性
  12. 如何下载矢量电子地图
  13. 装饰器只有python才有吗_Python装饰器入门详解
  14. JAVA自学知识点评定标准--自尚学堂马士兵
  15. iOS-AppStore上线被拒的各种理由...
  16. Uint 和 int 的区别
  17. 京东后台模板导入SKU报格式错误
  18. oracle dba 培训教程 第11章 索引的管理与维护
  19. java gef_GEF开发入门要点(个人经验)
  20. fcntl设置FD_CLOEXEC

热门文章

  1. IntelliJ IDEA for Mac的快速切换当前主题方案(Quick switch current scheme)
  2. Linux 如何安装程序的源代码软件包/源码程序包/源码包?
  3. 需求分析师与产品经理的区别
  4. mysql导入三个基本表_mysql 基础导入导出
  5. linux添加windows网络打印机,Linux Mint如何添加windows分享的网络打印机?
  6. mysql不支持子查询_MySQL不支持子查询优化一例
  7. pytorch dataset_【小白学PyTorch】16.TF2读取图片的方法
  8. 天线3db波束宽度_浅谈 Wi-Fi 天线(2)
  9. JAVA中使用bos做视频上传_JAVA语言之搭建物流BOS项目骨架
  10. 田忌赛马c语言程序设计,还是杭电1052田忌赛马