Python之web服务利器Flask生产环境部署实践【基于gunicorn部署生产环境】

     Python是一门非常友好的语言,学习成本很低,这也是我很喜欢写Python的原因之一,在与应用端或者是业务端做整合的时候我们经常会将模型或者是数据分析的应用做成可以被直接调用的web服务来提供外部的访问,在web服务搭建这一块,有很多的第三方库可以完成这一任务,这里列举出来我了解的web框架,欢迎补充:

Django: Python Web应用开发框架
Diesel:基于Greenlet的事件I/O框架
Flask:一个用Python编写的轻量级Web应用框架
Cubes:轻量级Python OLAP框架
Kartograph.py:创造矢量地图的轻量级Python框架
Web2py:全栈式Web框架
Pulsar:Python的事件驱动并发框架
Falcon:构建云API和网络应用后端的高性能Python框架
Bottle: 微型Python Web框架
Tornado:异步非阻塞IO的Python Web框架
webpy: 轻量级的Python Web框架

       对于我个人而言,Flask是我搭建web服务的首选,很轻量级,使用起来也很方便,简单的应用几乎是没有什么学习成本的,相信使用过的人对于下面这句话都不会陌生: 

      很简单的依据启动命令就可以将我们自己的应用或者是模块暴露成可被访问、调用的web服务了,很神奇的吧。

     说了Flask的很多好处,但是这是否意味着它是完美的了呢?其实并不是,很大程度上需要取决于你的应用复杂程度,今天遇上一个问题就是需要在生产环境里面部署Flask应用服务,之前这个问题我并没有去过多考虑,因为觉得开发环境和生产环境的部署方式是一样的,所以一直也就这么做着项目走过来了后面发现并不是这个样子的,我们来看一个简单的例子:

      上图是在windows下面我启动了本地的一个web服务,终端输出的提示信息以及警告信息,之前一直都忽略了这一行信息,其实这里的警告信息很简单就是说:不要使用这种方式在生产环境里面部署你的web服务,如果仅仅是用来开发、测试或者是调试什么的则就无所谓了,那么这是为什么呢?是因为:flask直接用于生产环境无论是处理高并发还是鲁棒性都有所欠缺,一般会配合WGSI容器来进行生产环境的部署

    所以这里就需要针对生产环境的部署去做一套方案了。我是参考了这里的方案,截图如下所示:

      我们参考的是【自主部署选项】这里的内容,截图如下所示:

     这里文档讲的比较简单,不过也大概看懂了使用的过程是比较简单。

     这里自己的实践思路就是【gunicorn+gevent】,首先来简单熟悉一下gevent:

官方解释 greenlet 是轻量级的并行编程,gevent 就是利用 greenlet 实现的基于协程(coroutine)的 python 的网络 library,通过使用greenlet提供了一个在libev事件循环顶部的高级别并发API。即 gevent 是对 greenlet 的高级封装。

      下面是从廖老师网站里面拿来的介绍:

     上面的内容理解了我们差不多就知道gevent是干什么的了。接下来就需要来了解一下gunicorn了,在了解和介绍gunicorn之前,我们先来看看WSGI是什么,下面是摘自百度百科的介绍:

WSGI介绍:
PythonWeb服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广泛接受, 它已基本达成它的可移植性方面的目标。WSGI 没有官方的实现, 因为WSGI更像一个协议. 只要遵照这些协议,WSGI应用(Application)都可以在任何服务器(Server)上运行, 反之亦然。
WSGI标准在 PEP333中定义并被许多框架实现,其中包括现广泛使用的django、flask框架。


诞生背景:
以前如何选择合适的Web应用程序框架成为困扰Python初学者的一个问题,这是因为,一般而言,Web应用框架的选择将限制可用的Web服务器的选择,反之亦然。那时的Python应用程序通常是为CGI,FastCGI,mod_python中的一个而设计,甚至是为特定Web服务器的自定义的API接口而设计的。WSGI(有时发音作'wiz-gee')是作为Web服务器与Web应用程序或应用框架之间的一种低级别的接口,以提升可移植Web应用开发的共同点。WSGI是基于现存的CGI标准而设计的。

      看了好多gunicorn介绍的资料,下面总结的一段话感觉是比较贴切的了:

Gunicorn是一个unix上被广泛使用的高性能的Python WSGI UNIX HTTP Server。和大多数的web框架兼容,并具有实现简单,轻量级,高性能等特点。gunicorn是支持wsgi协议的http服务器,gevent只是它支持的模式之一,是为了解决django、flask这些web框架自带wsgi server性能低下的问题。自带的webserver更多的是测试用途,线上发布时,最好使用高性能的wsgi server或者是联合nginx做uwsgi。

     毕竟是第一次接触到的东西,所以必要的背景内容和相关的介绍说明学习是很重要的对于我来说是这样的。初步熟悉和了解之后就可以开始实践了,首选是环境的搭建:

pip install gunicorn
pip install gevent

      完成了环境的搭建后,下面是一个简单的实例【myApp.py】:

#!usr/bin/env python
#encoding:utf-8
from __future__ import division


'''
__Author__:沂水寒城
功能: gunicorn+flask Demo
'''


from flask import *
#过滤掉警示信息
import warnings
warnings.filterwarnings("ignore")





app=Flask(__name__)




@app.route("/")
def init():
    '''
    初始化启动接口
    http://localhost:5000/
    '''
    return u"gunicorn+flask web服务正常启动........"




if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)



      启动命令如下所示:

gunicorn -w 10 -b 0.0.0.0:5000 myApp:app

    在Linux终端执行上面的命令后就可以看到相应的输出了,这里就不进行展示了,后面会有具体的实例。

    下午了解到的启动方式主要有两种,上面的直接命令行启动是第一种方式,第二种方式是基于配置文件的启动,这里就需要编写一个config.py的配置文件来对gunicorn的配置项进行配置了,我们在终端可以简单地通过下面的命令来查看gunicorn所有的配置选项:

gunicorn -h

      下面是所有的可选配置项信息:

usage: gunicorn [OPTIONS] [APP_MODULE]

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -m INT, --umask INT   A bit mask for the file mode on files written by
                        Gunicorn. [0]
  --worker-connections INT
                        The maximum number of simultaneous clients. [1000]
  --max-requests INT    The maximum number of requests a worker will process
                        before restarting. [0]
  --graceful-timeout INT
                        Timeout for graceful workers restart. [30]
  --access-logfile FILE
                        The Access log file to write to. [None]
  --reload-engine STRING
                        The implementation that should be used to power
                        :ref:`reload`. [auto]
  --preload             Load application code before the worker processes are
                        forked. [False]
  -D, --daemon          Daemonize the Gunicorn process. [False]
  --strip-header-spaces
                        Strip spaces present between the header name and the
                        the ``:``. [False]
  --certfile FILE       SSL certificate file [None]
  --log-syslog-to SYSLOG_ADDR
                        Address to send syslog messages. [udp://localhost:514]
  --statsd-prefix STATSD_PREFIX
                        Prefix to use when emitting statsd metrics (a trailing
                        ``.`` is added, []
  -w INT, --workers INT
                        The number of worker processes for handling requests.
                        [1]
  --max-requests-jitter INT
                        The maximum jitter to add to the *max_requests*
                        setting. [0]
  --no-sendfile         Disables the use of ``sendfile()``. [None]
  --reuse-port          Set the ``SO_REUSEPORT`` flag on the listening socket.
                        [False]
  --worker-tmp-dir DIR  A directory to use for the worker heartbeat temporary
                        file. [None]
  -u USER, --user USER  Switch worker processes to run as this user. [0]
  --reload              Restart workers when code changes. [False]
  --chdir CHDIR         Chdir to specified directory before apps loading.
                        [/root/cgb/demo]
  --access-logformat STRING
                        The access log format. [%(h)s %(l)s %(u)s %(t)s
                        "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"]
  --limit-request-fields INT
                        Limit the number of HTTP headers fields in a request.
                        [100]
  --ca-certs FILE       CA certificates file [None]
  --spew                Install a trace function that spews every line
                        executed by the server. [False]
  --forwarded-allow-ips STRING
                        Front-end's IPs from which allowed to handle set
                        secure headers. [127.0.0.1]
  --do-handshake-on-connect
                        Whether to perform SSL handshake on socket connect
                        (see stdlib ssl module's) [False]
  -R, --enable-stdio-inheritance
                        Enable stdio inheritance. [False]
  --paste STRING, --paster STRING
                        Load a PasteDeploy config file. The argument may
                        contain a ``#`` [None]
  --proxy-allow-from PROXY_ALLOW_IPS
                        Front-end's IPs from which allowed accept proxy
                        requests (comma separate). [127.0.0.1]
  --logger-class STRING
                        The logger you want to use to log events in Gunicorn.
                        [gunicorn.glogging.Logger]
  --keep-alive INT      The number of seconds to wait for requests on a Keep-
                        Alive connection. [2]
  -c CONFIG, --config CONFIG
                        The Gunicorn config file. [None]
  --log-level LEVEL     The granularity of Error log outputs. [info]
  --paste-global CONF   Set a PasteDeploy global config variable in
                        ``key=value`` form. [[]]
  --pythonpath STRING   A comma-separated list of directories to add to the
                        Python path. [None]
  --reload-extra-file FILES
                        Extends :ref:`reload` option to also watch and reload
                        on additional files [[]]
  --capture-output      Redirect stdout/stderr to specified file in
                        :ref:`errorlog`. [False]
  --ciphers CIPHERS     SSL Cipher suite to use, in the format of an OpenSSL
                        cipher list. [None]
  --keyfile FILE        SSL key file [None]
  -k STRING, --worker-class STRING
                        The type of workers to use. [sync]
  --log-config-dict LOGCONFIG_DICT
                        The log config dictionary to use, using the standard
                        Python [{}]
  --log-syslog-prefix SYSLOG_PREFIX
                        Makes Gunicorn use the parameter as program-name in
                        the syslog entries. [None]
  --backlog INT         The maximum number of pending connections. [2048]
  --limit-request-line INT
                        The maximum size of HTTP request line in bytes. [4094]
  -p FILE, --pid FILE   A filename to use for the PID file. [None]
  -b ADDRESS, --bind ADDRESS
                        The socket to bind. [['127.0.0.1:8000']]
  --disable-redirect-access-to-syslog
                        Disable redirect access logs to syslog. [False]
  --limit-request-field_size INT
                        Limit the allowed size of an HTTP request header
                        field. [8190]
  -n STRING, --name STRING
                        A base to use with setproctitle for process naming.
                        [None]
  --error-logfile FILE, --log-file FILE
                        The Error log file to write to. [-]
  --ssl-version SSL_VERSION
                        SSL version to use. [_SSLMethod.PROTOCOL_SSLv23]
  --cert-reqs CERT_REQS
                        Whether client certificate is required (see stdlib ssl
                        module's) [0]
  -g GROUP, --group GROUP
                        Switch worker process to run as this group. [0]
  --proxy-protocol      Enable detect PROXY protocol (PROXY mode). [False]
  --threads INT         The number of worker threads for handling requests.
                        [1]
  -t INT, --timeout INT
                        Workers silent for more than this many seconds are
                        killed and restarted. [30]
  --dogstatsd-tags DOGSTATSD_TAGS
                        A comma-delimited list of datadog statsd (dogstatsd)
                        tags to append to statsd metrics. []
  --suppress-ragged-eofs
                        Suppress ragged EOFs (see stdlib ssl module's) [True]
  --log-config FILE     The log config file to use. [None]
  --initgroups          If true, set the worker process's group access list
                        with all of the [False]
  --check-config        Check the configuration. [False]
  --log-syslog          Send *Gunicorn* logs to syslog. [False]
  --log-syslog-facility SYSLOG_FACILITY
                        Syslog facility name [user]
  --statsd-host STATSD_ADDR
                        ``host:port`` of the statsd server to log to. [None]
  -e ENV, --env ENV     Set environment variable (key=value). [[]]

     感觉有很多很多,不过不是说所有的都是需要去手动配置的,我们只需要配置最常使用到的几个就行了,下面是我编写的一个配置文件:

#!usr/bin/env python
#encoding:utf-8


import os
import gevent.monkey
gevent.monkey.patch_all()
import multiprocessing


#开发环境可以打开,生产环境可以
#debug = True  

#用于控制errorlog的信息级别,可以设置为debug、info、warning、error、critical
loglevel = 'debug'

#监听地址+端口
bind = "0.0.0.0:5000"

#定义日志存储
if not os.path.exists('log/'):
    os.makedirs('log/')
pidfile = "log/gunicorn.pid"
#访问日志
accesslog = "log/access.log"
#错误日志
errorlog = "log/debug.log"

#开启后台运行,默认值为False
daemon = True

#启动的进程数,推荐值为:CPU核数*2+1
workers = multiprocessing.cpu_count()*2+1

#指开启的每个工作进程的模式类型,默认为sync模式,也可使用gevent模式
worker_class = 'gevent'
x_forwarded_for_header = 'X-FORWARDED-FOR'

        个人感觉写得是很清晰的了,相应的配置项都已经写上了注释说明了方便具体的改动处理。我们使用第一种启动方式启动,下面是具体的输出截图:

命令:  

gunicorn -w 4 -b 172.19.6.213:5000 myApp:app

     启动命令中,我们设置了4个进程,从结果来看一共有4个不同的pid编号说明启动了4个不同的进程。关闭可以使用【Ctrl+C】的方式,截图如下所示:

      接下来使用第二种启动方式执行,命名如下:

gunicorn --config=config.py API:app

      结果截图如下所示:

    第二种方式是基于配置文件的启动方式,这里我们启动的同时还生成了日志文件:

    首先来看debug.log的内容,因为内容比较多,这里只看最后几行:

    然后是看gunicorn.pid的内容:

    细心的你是不是发现了什么呢?57523这个pid是不是。

    最后看access.log的内容,这是访问日志存储文件,因为我们没有访问接口,所以文件就是空的。

     到这里整个的生产环境部署实践差不多就结束了,感觉也是收获很多,学海无涯啊!

发布了540 篇原创文章 · 获赞 1320 · 访问量 340万+

猜你喜欢

转载自blog.csdn.net/Together_CZ/article/details/105518419