@html
所謂WSGI
.
WSGI是Web服務器網關接口,它是一個規範,描述了Web服務器如何與Web應用程序通訊,以及如何與Web應用程序連接在一塊兒處理一個請求(接收請求、處理請求、響應請求).
.
基於wsgi運行的框架有Bottle、Django、Flask,用於解析動態HTTP請求.
.
---------⬇️
支持WSGI的服務器
.
wsgiref
Python自帶的服務器.
.
Gunicorn
用於Linux的python wsgi Http服務器,經常使用於各類Django、Flask結合部署服務器.
.
mode_wsgi
實現了Apache與wsgi應用程序的結合.
.
uWSGI
C語言開發,快速,自我修復,開發人員友好的WSGI服務器,用於Python Web應用程序的專業部署和開發.
---------⬆️
.
在部署Python程序的Web應用程序時,能夠根據性能的需求,選擇合適的wsgi server,不一樣的wsgi server區別在於併發支持上,有單線程、多進程、多線程、協程的區別,其功能類似,無非是請求路由,執行對應的函數,返回處理結果.python
關於Django環境中的wsgi.py文件
上圖是Django環境中的wsgi.py文件.
.
Django的主要部署平臺是WSGI,其用於Web服務器和應用程序的Python標準.
.
Django的startproject管理命令設置一個簡單的默認WSGI設置,能夠根據需求爲咱們的項目進行調整,並指示任何符合WSGI的應用程序服務器使用.
.
application使用WSGI部署的關鍵概念是應用程序服務器用於與代碼通訊的application可調用,它一般在服務器可訪問的Python模塊中做爲名爲application的對象提供.
.
startproject命令建立包含這樣的application可調用的文件:
<project_name>/wsgi.py,它被Django的開發服務器和生產WSGI部署使用,WSGI服務器從其配置中獲取application可調用的路徑。Django的內置服務器,即runserver命令,從WSGI_APPLICATION設置讀取它.nginx
爲何使用Nginx,uWSGI
.
首先,nginx是對外的服務接口,外部瀏覽器經過url訪問nginx.
.
而後,nginx接收到瀏覽器發送過來的http請求,將包進行解析並分析url。若是是靜態文件請求就訪問用戶給nginx配置的靜態文件目錄,直接返回用戶請求的靜態文件,若是不是靜態文件請求(即動態請求),那麼nginx就將請求轉發給uwsgi,uwsgi接收到請求以後將包進行處理,處理成wsgi能夠接收的格式,併發給wsgi。wsgi根據請求調用應用程序中的某個文件,或者某個文件中的某個函數,最後處理完將返回值再次交給wsgi,wsgi將返回值進行打包,打包成uwsgi可以接收的格式,uwsgi接收wsgi發送的請求,並轉發給nginx,nginx最終將返回值返回給瀏覽器.
.
最後,要知道第一級的nginx並非必須的,uwsgi徹底能夠完成整個的和瀏覽器交互的流程,可是要考慮到下面3種狀況.
.
1.安全問題
程序不能直接被瀏覽器訪問到,而是經過nginx,nginx只開發某個接口.
uwsgi自己是內網接口,這樣運維人員在nginx中加上安全性的限制,能夠達到保護程序的做爲.
.
2.負載均衡問題
一個uwsgi極可能不夠用,即便開多個work也是不行,畢竟一臺機器的cpu和內存是有限的.
而使用nginx作代理,一個nginx能夠代理多臺uwsgi完成uwsgi的負載均衡.
.
3.靜態文件問題
用Django或是uwsgi來負責靜態文件的處理是很浪費的行爲,它們自己對文件的處理也不如nginx,因此整個靜態文件的處理都直接由nginx完成,靜態文件的訪問徹底不去通過uwsgi以及其後面的邏輯.程序員
下面將對Nginx、WSGI、uwsgi、uWSGI、Django之間的關係進行梳理.
.
---------⬇️
wsgi
全稱web server gateway interface,wsgi不是服務器,也不是Python模塊,而是一種通訊協議.
其用於描述web server如何與web application進行通信.
運行在wsgi上的web框架有Bottle、Flask、Django.
.
uwsgi
與wsgi同樣,是通訊協議,是uWSGI服務器的單獨協議,用於定義傳輸信息的類型.
.
uWSGI
是一個web服務器,實現了WSGI協議,uwsgi協議.
.
Nginx
web服務器,更加安全,更好的處理靜態資源,緩存功能,負載均衡.
nginx的強勁性能,配合我WSGI服務器會更加安全,性能有保障.
.
Django
高級的Python框架,用於快速開發,解決web開發的大部分麻煩,程序員能夠更加專一於業務邏輯,無序從新造輪子.
---------⬆️
.
邏輯圖:
---------⬇️
web服務器
傳統的C/S架構,請求的過程是:
客戶端 > 服務器
服務器 > 客戶端
服務器就是:1.接收請求 2.處理請求 3.返回響應
.
web框架層
HTTP的動態數據交給web框架,例如Django遵循MTV模式處理請求.
HTTP協議使用url定位資源,urls.py將路由請求交給views視圖處理,而後返回一個結果,完成一次請求.
web框架使用者只須要處理業務的邏輯便可.
---------⬆️
.
若是將一次通訊轉化爲「對話」的過程:
Nginx:「Hello WSGI,我剛收到了一個請求,你準備下,而後讓Django來處理吧。」
WSGI:「好的,Nginx,我立刻設置環境變量,而後把請求交給Django。」
Django:「謝謝 WSGI,我處理完請求立刻給你響應結果。」
WSGI:「好的,我在等。」
Django:「搞定啦,麻煩WSGI把響應結果傳遞給Nginx。」
WSGI:「Very good Nginx,響應結果請收好,已經按照要求傳遞給你了。」
Nginx:「好的,我這就把響應結果交給客戶,合做愉快。」web
安裝uWSGIapache
# 進入虛擬環境,安裝uWSGI (venv) [root@master ~]# pip3.6 install uwsgi # 檢查uWSGI版本 (venv) [root@master ~]# uwsgi --version 2.0.17.1 # 檢查uWSGI Python版本 (venv) [root@master ~]# uwsgi --python-version 3.6.7
運行簡單的uWSGIdjango
test.py文件以下:瀏覽器
def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'Hello World'] # Python3
運行命令以下:緩存
uwsgi --http :8000 --wsgi-file test.py """參數詳解: --http :8000 -> 使用http協議,端口8000 --wsgi-file test.py -> 加載test.py文件 """
運行後,可從瀏覽器訪問:
tomcat
uWSGI運行Django環境
.
----------------------------------
經過命令運行Django環境# 在項目根目錄下執行以下命令 uwsgi --http :8000 --module project.wsgi """參數詳解: --http :8000 -> 使用http協議,端口8000 ----module -> 加載project項目下的wsgi模塊 """.
----------------------------------
使用腳本運行Django環境
.
uWSGI支持ini、xml等多種配置方式.
這裏將以ini爲例,在/etc/目錄下新建uwsgi_nginx.ini配置文件,以下:# 項目配置文件 [uwsgi] # 項目的絕對路徑 定位到第一層 chdir = /root/oldboy # 指定項目的wsgi文件路徑(從項目的根路徑開始) module = oldboy.wsgi # 指定虛擬解釋器的第一層路徑 home = /root/Envs/oldboy # 指定經過uwsgi啓動多少個進程 processes = 4 # 若是你已經配置了nginx,請使用這個socket鏈接 socket = 0.0.0.0:9999 # 若是你沒有配置nginx,想經過uwsgi直接啓動web服務,請使用這個http鏈接,指明http協議 # http = 0.0.0.0:9999 # 用於在退出uwsgi環境後清空環境變量 vacuum = true指定配置文件啓動命令:
uwsgi --ini /etc/uwsgi_nginx.ini
uWSGI熱加載Python程序
.
在啓動命令的後面加上--py-autoreload=1便可# 命令啓動 uwsgi --http :8000 --module mysite.wsgi --py-autoreload=1 # 配置文件啓動 uwsgi --ini uwsgi.ini --py-autoreload=1此時修改Django代碼,uWSGI會自動加載Django程序,頁面生效.
這裏咱們只講解Nginx配置文件部分
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; keepalive_timeout 65; # 負載集羣 upstream load { server 192.168.1.100:9999; server 192.168.1.200:9999; server 192.168.1.300:9999; } server { listen 80; server_name 192.168.43.149; location / { # nginx自帶的ngx_http_uwsgi_module模塊,起到nginx和uwsgi交互的做用 # 經過uwsgi_pass指定服務器地址和協議,將動態請求轉發給uwsgi處理 uwsgi_pass load; include /usr/local/nginx1.12/conf/uwsgi_params; } # nginx處理靜態頁面資源 location /static { alias /data/static/; } # nginx處理媒體資源 location /media { alias/data/media/; } } }
配置完後重啓Nginx,便可實現其功能.
supervisor是基於Python的任務管理工具,用於自動運行各類後臺任務。固然咱們也能直接使用Linux的nohup命令是任務自動後臺運行,但若是要重啓任務,就得手動去kill掉任務進程。這樣很繁瑣,並且一旦程序錯誤致使進程退出的話,系統也沒法自動重載任務。
下載
# 因爲supervisor在python3下沒法使用,所以只能用python2去下載 yum install python-setuptools easy_install supervisor
經過下面的命令生成supervisor的配置文件
echo_supervisord_conf > /etc/supervisord.conf
而後在/etc/supervisord.conf末尾添加以下代碼
[program:django_test] # [program:項目名稱] command=/root/Envs/djang1.11.11/bin/uwsgi --ini /root/django_test/uwsgi.ini # 程序啓動命令 autostart=true # 在supervisord啓動的時候也自動啓動,可以使uWSGI程序被殺掉後自動運行 # 這裏咱們只使用到了上面兩個參數⬆️ # startsecs=10 # 啓動10秒後沒有異常退出,就表示進程正常啓動了,默認爲1秒 # autorestart=true # 程序退出後自動重啓,可選值有:[unexpected,true,false],默認爲unexpected,表示進程被意外殺死後才重啓 # startretries=3 # 啓動失敗自動重試次數,默認是3 # user=django1.11.11 # 用哪一個用戶啓動進程,默認爲root # priority=999 # 進程啓動優先級,默認999,值小的優先啓動 # redirect_stderr=true # 把stderr重定向到stdout,默認false # stdout_logfile_maxbytes=20MB # stdout 日誌文件大小,默認50MB # stdout_logfile_backups = 20 # stdout 日誌文件備份數,默認是10 # stdout # 日誌文件,須要注意當指定目錄不存在時沒法正常啓動,因此須要手動建立目錄(supervisord 會自動建立日誌文件) # stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out # stopasgroup=false # 默認爲false,進程被殺死時,是否向這個進程組發送stop信號,包括子進程 # killasgroup=false # 默認爲false,向進程組發送kill信號,包括子進程
其中command是結合virtualenv的命令和supervisor的精髓:
command=/root/Envs/djang1.11.11/bin/uwsgi --ini /root/django_test/uwsgi.ini command=/root/Envs/djang1.11.11/bin/uwsgi --uwsgi 0.0.0.0:8000 --chdir /root/django_test --home=/root/venv --module django_test.wsgi # --chdir:指定項目的根 # --home:指的是虛擬環境目錄 # --module:找到Django項目環境中的wsgi.py文件
啓動supervisor
# 啓動supervisor supervisord -c /etc/supervisord.conf # 重啓my項目 supervisorctl -c /etc/supervisord.conf restart my supervisorctl -c /etc/supervisord.conf [start|stop|restart] [program-name|all]
從新加載supervisor
supervisorctl update # 更新新的配置到supervisord supervisorctl reload # 從新啓動配置中的全部程序 supervisorctl start program_name # 啓動某個進程(program_name=你配置中寫的程序名稱) supervisorctl # 查看正在守候的進程 pervisorctl stop program_name # 中止某一進程 (program_name=你配置中寫的程序名稱) supervisorctl restart program_name # 重啓某一進程 (program_name=你配置中寫的程序名稱) supervisorctl stop all # 中止所有進程 # 注意:顯示用stop中止掉的進程,用reload或者update都不會自動重啓。
mysite/settings.py
# 此參數會將將全部STATICFILES_DIRS中全部文件夾中的文件,以及各app中static中的文件都複製到指定的路徑下 STATIC_ROOT='/data/static' STATIC_URL='/static' STATICFILES_DIRS=[ os.path.join(BASE_DIR, 'static'), ]
配置完畢後,運行命令:
python3.6 manage.py collectstatic
上面的命令會收集全部咱們項目中全部的靜態文件並保存到STATIC_ROOT指定的路徑下.把這些文件放到一塊兒是爲了用nginx等部署的時候更方便.