結合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 部署應用時,不需要使用本地服務器。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM