• 结合uWSGI和Nginx部署flask项目


      在开发环境,我们一般使用python起一个web服务即可访问,但是对于生产环境来说,我们一般使用nginx+uWSGI的方式进行部署。

    使用Nginx优点:

    • 安全:不管什么请求都要经过代理服务器,这样就避免了外部程序直接攻击web服务器
    • 负载均衡:根据请求情况和服务器负载情况,将请求分配给不同的web服务器,保证服务器性能
    • 提高web服务器的IO性能:对于一些静态文件,可以直接由反向代理处理,不经过web服务器

    相关概念:

      wsgi web应用程序之间的接口。它的作用就像是桥梁,连接在web服务器和web应用框架之间。
      uwsgi 是一种传输协议,用于定义传输信息的类型。
      uWSGI 是实现了uwsgi协议WSGI的web服务器。

    1. 添加测试项目

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        return 'flask project'
    
    
    @app.route("/user/<int:uid>")
    def user_profile(uid):
        return f'user id:{uid}'
    
    
    if __name__ == '__main__':
        app.run()

    本项目是基于虚拟环境进行搭建,具体安装查看virtualenv相关博客

    2.创建新的虚拟环境,并安装uwsgi

    mkvirtualenv flask_env
    
    pip3 install uwsgi

    3. 在本项目下创建uwsgi配置文件,添加内容如下:

      [uwsgi]
    module = app:app # 相当于命令下的-w 指定模块(wsgi-file,callable 这两个可以被注视掉)
    #http = 127.0.0.1:5000 socket = 127.0.0.1:5000 # 支持http+socket两种方式,这里选用socket virtualenv = /root/python_env/flask_project # 如果使用虚拟环境,需要进行执行 chdir = /data/python_projects/flask_project # 指定项目路径 #wsgi-file = app.py # 项目入口文件 #callable = app # flask应用对象 process = 2 # 进程数 threads = 2 # 每个进程开启的线程数 buffer-size = 32768 master = true # 主进程 daemonize = %(chdir)/uwsgi/uwsgi.log # 指的后台启动 日志输出的地方 pidfile = %(chdir)/uwsgi/uwsgi.pid # 保存主进程的进程号
    py-autoreload=1 #热加载开启
     touch-logreopen = %(chdir)/uwsgi/touchforlogrotate # 日志分割监听文件
     stats = 127.0.0.1:9191  # 添加监听  使用nc  127.0.0.1 9191 查看 (nc 安装:yum -y install nmap-ncat)
    thunder-lock = true
    #防止惊群
    harakiri = 60
    #超时时间(秒)
    vacuum = true  #自动移除unix Socket和pid文件当服务停止的时候 

      

    完整配置项:

    socket : 地址和端口号,例如:socket = 127.0.0.1:50000
    
    processes : 开启的进程数量
    
    workers : 开启的进程数量,等同于processes(官网的说法是spawn the specified number of  workers / processes)
    
    chdir : 指定运行目录(chdir to specified directory before apps loading)
    
    wsgi-file : 载入wsgi-file(load .wsgi file)
    
    stats : 在指定的地址上,开启状态服务(enable the stats server on the specified address)
    
    threads : 运行线程。由于GIL的存在,我觉得这个真心没啥用。(run each worker in prethreaded mode with the specified number of threads)
    
    master : 允许主进程存在(enable master process)
    
    daemonize : 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器(daemonize uWSGI)。实际上最常用的,还是把运行记录输出到一个本地文件上。
    
    log-maxsize :以固定的文件大小(单位KB),切割日志文件。 例如:log-maxsize = 50000000  就是50M一个日志文件。 
    
    pidfile : 指定pid文件的位置,记录主进程的pid号。
    
    vacuum : 当服务器退出的时候自动清理环境,删除unix socket文件和pid文件(try to remove all of the generated file/sockets)
    
    disable-logging : 不记录请求信息的日志。只记录错误以及uWSGI内部消息到日志中。如果不开启这项,那么你的日志中会大量出现这种记录:
    
    [pid: 347|app: 0|req: 106/367] 117.116.122.172 () {52 vars in 961 bytes} [Thu Jul  7 19:20:56 2016] POST /post => generated 65 bytes in 6 msecs (HTTP/1.1 200) 2 headers in 88 bytes (1 switches on core 0)
    
    log-maxsize: 日志大小,当大于这个大小会进行切分 (Byte)
    
    log-truncate: 当启动时切分日志

    4.启动服务

    uwsgi --ini config.ini

    5.配置nginx代理转发

            location / {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:5000;
            }

    因为转发之后的通信是使用的uwsgi://127.0.0.1:5000进行通信,所以uwsgi配置socket方式


    如果使用http的方式进行通信的话:
    location / {
    proxy_pass http://127.0.0.1:5000;
    }

    其他命令:

    # 重启uwsgi服务
    uwsgi  --reload uwsgi.pid
    
    # 停止uwsgi服务
    uwsgi --stop uwsgi.pid

    命令下的 服务启动:

    $ uwsgi -s /tmp/yourapplication.sock --manage-script-name --mount /yourapplication=myapp:app
    --manage-script-name 会把 SCRIPT_NAME 处理移向 uwsgi , 因为 uwsgi 会更智能一些。与 --mount 联用可以把向 /yourapplication 发送的请求 重定向到 myapp:app 。如果应用可以在根级别访问,那么可以使用单个 / 来代替 /yourapplication 。 myapp 指 flask 应用的文件名称(不含扩展 名)或者提供 app 的模块名称。 app 在应用内部可被调用(通常是 app = Flask(__name__) )。
    
    如果要把应用部署于一个虚拟环境,则还需要加上 --virtualenv /path/to/virtual/environment 。可能还需要根据项目所使用的 Python 版本相应地加上 --plugin python 或者 --plugin python3 。

    添加日志分割:

      uwsgi没有提供按天的日志切割配置,只提供了一个log-maxsize配置,当文件达到多大的时候自动切分,对于查找历史日志还是很不方便。

    这里可以用mv+touch-logreopen参数,移动日志文件后,让uwsgi重新打开日志记录,不过需要配合sh+crontab
    配置文件添加:
    touch-logreopen = %d./touchforlogrotat #指定监听文件,修改后重新打开日志


    这里我们指定日志文件就在项目目录下叫uwsgi.daemonize.log,监听项目目录下的touchforlogrotat文件,如果文件发生变化,就重新打开日志,我们可以先将当前的uwsgi.daemonize.log文件移动到别的地发,再touch一下touchforlogrotat,之前的文件便停止写入,重新生成了一个叫uwsgi.daemonize.log文件。


    在当前项目下新建一个touchforlogrotate.sh,并新建日志文件备份的日志,这里就放在项目中的logs文件夹

    #!/bin/bash
    
    DIR=`echo $(cd "$(dirname "$0")"; pwd)`
    LOGDIR="${DIR}/logs"
    
    sourcelogpath="${DIR}/uwsgi.daemonize.log"
    touchfile="${DIR}/touchforlogrotate"
    
    
    DATE=`date -d "yesterday" +"%Y%m%d"`
    destlogpath="${LOGDIR}/uwsgi.daemonize.${DATE}.log"
    
    mv $sourcelogpath $destlogpath
    touch $touchfile

    crontab定时调用

    0 0 * * * sh /projectpath/touchforlogrotate.sh

    注意点:

      1.请务必把 app.run() 放在 if __name__ == '__main__': 内部或者放在单独 的文件中,这样可以保证它不会被调用。因为,每调用一次就会开启一个本地 WSGI 服务器。当我们使用 uWSGI 部署应用时,不需要使用本地服务器。

  • 相关阅读:
    论文阅读笔记(四十五)【CVPR2020、AAAI2020】:Relation Feature 的应用
    论文阅读笔记(四十四)【ICCV2017】:Deeply-Learned Part-Aligned Representations for Person Re-Identification
    论文阅读笔记(四十三)【AAAI2020】:Rethinking Temporal Fusion for Video-based Person Re-identificationon Semantic and Time Aspect
    论文阅读笔记(四十二)【AAAI2019】:STA:Spatial-Temporal Attention for Large-Scale Video-based Person Re-Identification
    论文阅读笔记(四十一)【CVPR2017】:Learning Deep Context-aware Features over Body and Latent Parts for Person Re-identification
    论文阅读笔记(四十)【CVPR2017】:Human Semantic Parsing for Person Re-identification
    论文阅读笔记(三十九)【CVPR2017】:Spindle Net Person Re-identification with Human Body Region Guided Feature Decomposition and Fusion
    论文阅读笔记(三十八)【AAAI2020】:Semantics-Aligned Representation Learning for Person Re-identification
    学习笔记_SpringBoot2
    学习笔记_SpringBoot1
  • 原文地址:https://www.cnblogs.com/xingxia/p/python_nginx_uwsgi.html
Copyright © 2020-2023  润新知