WSGI是什么?
WSGI,全稱 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是為 Python 語言定義的 Web 服務器和 Web 應用程序或框架之間的一種簡單而通用的接口。自從 WSGI 被開發出來以后,許多其它語言中也出現了類似接口。
WSGI 的官方定義是,the Python Web Server Gateway Interface。從名字就可以看出來,這東西是一個Gateway,也就是網關。網關的作用就是在協議之間進行轉換。
WSGI 是作為 Web 服務器與 Web 應用程序或應用框架之間的一種低級別的接口,以提升可移植 Web 應用開發的共同點。WSGI 是基於現存的 CGI 標准而設計的。
很多框架都自帶了 WSGI server ,比如 Flask,webpy,Django、CherryPy等等。當然性能都不好,自帶的 web server 更多的是測試用途,發布時則使用生產環境的 WSGI server或者是聯合 nginx 做 uwsgi 。
也就是說,WSGI就像是一座橋梁,一邊連着web服務器,另一邊連着用戶的應用。但是呢,這個橋的功能很弱,有時候還需要別的橋來幫忙才能進行處理。WSGI 的作用如圖所示:
WSGI的作用
WSGI有兩方:“服務器”或“網關”一方,以及“應用程序”或“應用框架”一方。服務方調用應用方,提供環境信息,以及一個回調函數(提供給應用程序用來將消息頭傳遞給服務器方),並接收Web內容作為返回值。
所謂的 WSGI中間件同時實現了API的兩方,因此可以在WSGI服務和WSGI應用之間起調解作用:從WSGI服務器的角度來說,中間件扮演應用程序,而從應用程序的角度來說,中間件扮演服務器。“中間件”組件可以執行以下功能:
- 重寫環境變量后,根據目標URL,將請求消息路由到不同的應用對象。
- 允許在一個進程中同時運行多個應用程序或應用框架。
- 負載均衡和遠程處理,通過在網絡上轉發請求和響應消息。
- 進行內容后處理,例如應用XSLT樣式表。
WSGI 的設計確實參考了 Java 的 servlet
uWSGI
uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換。
要注意 WSGI / uwsgi / uWSGI 這三個概念的區分。
- WSGI看過前面小節的同學很清楚了,是一種通信協議。
- uwsgi同WSGI一樣是一種通信協議。
- 而uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。
uwsgi協議是一個uWSGI服務器自有的協議,它用於定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型描述,它與WSGI相比是兩樣東西。
為什么有了uWSGI為什么還需要nginx?因為nginx具備優秀的靜態內容處理能力,然后將動態內容轉發給uWSGI服務器,這樣可以達到很好的客戶端響應。
接下來,我們要看看 uWSGI 的安裝配置與使用。
安裝
uWSGI 的安裝很簡單:
pip install uwsgi
現在我們試下將 Django 跑起來。我們先在 virtualenv 創建一個 Django Project:
[root@nowamagic ~]# cd nowamagic_venv [root@nowamagic nowamagic_venv]# source bin/activate (nowamagic_venv)[root@nowamagic nowamagic_venv]# django-admin.py startproject nowamagic_pj
virtualenv 的路徑與目錄文件如下:
Django Project 的路徑與目錄文件如下:
測試uwsgi
在你的服務器上寫一個test.py:
# test.py def application(env, start_response): start_response('200 OK', [('Content-Type','text/html')]) return "Hello World"
我的 test.py 的路徑是 /root/nowamagic_venv/nowamagic_pj/test.py,執行以下命令:
[root@nowamagic ~]# cd nowamagic_venv [root@nowamagic nowamagic_venv]# source bin/activate (nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8001 --wsgi-file /root/nowamagic_venv/nowamagic_pj/test.py
訪問網頁 http://115.28.0.89:8001/,OK,顯示 Hello World,說明 uwsgi 安裝成功。
測試你的 Django 項目
前面我們用 django-admin.py startproject nowamagic_pj 創建了一個項目,現在我們用 Django 自帶的 Web 服務器看看我們的項目有沒出問題。還是進入我們虛擬環境:
[root@nowamagic ~]# cd nowamagic_venv [root@nowamagic nowamagic_venv]# source bin/activate (nowamagic_venv)[root@nowamagic nowamagic_venv]# python2.7 /root/nowamagic_venv/nowamagic_pj/manage.py runserver 0.0.0.0:8002
執行這個命令報錯:No module named django.core.management,原因應該是裝了多個版本的Python導致的。命令指定文件路徑就行,丑是丑些了
(nowamagic_venv)[root@nowamagic nowamagic_venv]# /usr/local/bin/python2.7 /root/nowamagic_venv/nowamagic_pj/manage.py runserver 0.0.0.0:8002
OK,啟動 Django 自帶的服務器了,我們再訪問 http://115.28.0.89:8002/,成功顯示:
說明 Djanggo 項目也沒問題。
連接Django和uwsgi
最后一步了,我們要把uwsgi與Django連接起來。
編寫django_wsgi.py文件,將其放在與文件manage.py同一個目錄下。我的放在 /root/nowamagic_venv/nowamagic_pj/ 下:
#!/usr/bin/env python # coding: utf-8 import os import sys # 將系統的編碼設置為UTF8 reload(sys) sys.setdefaultencoding('utf8') os.environ.setdefault("DJANGO_SETTINGS_MODULE","nowamagic_pj.settings") from django.core.handlers.wsgi import WSGIHandler application = WSGIHandler()
注意不要直接 copy,有個地方要改:注意到語句os.environ.setdefault。比如我的項目為nowamagic_pj,則語句應該是 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nowamagic_pj.settings")
OK,進入虛擬環境執行指令:
[root@nowamagic ~]# cd nowamagic_venv [root@nowamagic nowamagic_venv]# source bin/activate (nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8000 --chdir /root/nowamagic_venv/nowamagic_pj/ --module django_wsgi
成功顯示 Django It Works 頁面。
這樣,你就可以在瀏覽器中訪問你的Django程序了。所有的請求都是經過uwsgi傳遞給Django程序的。
這里我們介紹了如何把uwsgi與Django連接起來,在下一篇將繼續介紹如何將uwsgi與Nginx連接。
上一篇介紹了 uWSGI 來部署 Django 程序,但在在生產環境中單單只有 uWSGI 是不夠的,Nginx是必不可少的工具。
先安裝 Nginx,可以參照前面的小節:使用RPM安裝Nginx。
Nginx 配置
在 nginx.conf 上加入/修改,我的 server 配置如下(一切從簡……):
server { listen 80; server_name 115.28.0.89; #server_name localhost; access_log /home/nowamagic/logs/access.log; error_log /home/nowamagic/logs/error.log; #root /root/nowamagic_venv/nowamagic_pj; location / { uwsgi_pass 127.0.0.1:8077; #include uwsgi_params; include /etc/nginx/uwsgi_params; #uwsgi_pass 127.0.0.1:8077; #uwsgi_param UWSGI_SCRIPT index; #uwsgi_param UWSGI_PYHOME $document_root; #uwsgi_param UWSGI_CHDIR $document_root; } access_log off; }
注意保證配置里寫的目錄 /home/nowamagic/logs/ 和 /home/nowamagic/logs/ 存在,接下來就沒啥問題了,Nginx 配置很簡單。
uWSGI 配置
前面我們是直接使用命令行來啟動 uWSGI,在實際部署環境中,我們常用的是配置文件的方式,而非命令行的方式。
我的 Django 程序目錄:/root/nowamagic_venv/nowamagic_pj/
這里讓 Nginx 采用 8077 端口與 uWSGI 通訊,請確保此端口沒有被其它程序采用。
uWSGI 支持多種配置文件格式,比如 xml,ini,json 等等都可以。
1. xml 配置
請確定你在上一節中的django_wsgi.py文件已經存在了。新建一個XML文件:nowamagic_pj.xml,將它放在 /root/nowamagic_venv/nowamagic_pj 目錄下
<uwsgi> <socket>127.0.0.1:8077</socket> <listen>80</listen> <master>true</master> <pythonpath>/root/nowamagic_venv/nowamagic_pj</pythonpath> <processes>1</processes> <logdate>true</logdate> <daemonize>/var/log/uwsgi.log</daemonize> <plugins>python</plugins> </uwsgi>
然后執行命令:
uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml
or
/usr/local/bin/uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml
加載指定的xml配置文件。當使用命令行參數時,可以使用簡化命令“-x”。當然也可以不簡寫:
uwsgi --xml /etc/nowamagic.xml
甚至如果在命令行的最后一個參數以“.xml”結尾,那么就隱含將加載該xml文件作為配置。
uwsgi /etc/nowamagic.xml
有時候因各種環境問題,-x --xml 命令識別不了,可以使用下面的 ini 配置方式:
2. ini 配置
[uwsgi] vhost = false plugins = python socket = 127.0.0.1:8077 master = true enable-threads = true workers = 1 wsgi-file = /root/nowamagic_venv/nowamagic_pj/nowamagic_pj/wsgi.py virtualenv = /root/nowamagic_venv chdir = /root/nowamagic_venv/nowamagic_pj
然后執行命令:
uwsgi --ini /root/nowamagic_venv/nowamagic_pj.ini&
uwsgi 這樣就啟動起來了。如果無意外的話,就能在網上訪問你的 Python 項目了。
小插曲
我在配置完 Nginx 和 uWSGI 之后,訪問時顯示 502 錯誤。查看 uWSGI 啟動信息,發現這么一條:ImportError: No module named django.core.wsgi。
然后推斷,我的 CentOS 上的 Python 版本是 2.4.3,然后進入 virtualenv,執行:
python
<<< import django
<<< from django.core.wsgi import get_wsgi_application
<<<
則沒報錯,因為我的虛擬環境里的 Python 版本是 2.7.5。推斷成立,但是虛擬環境里的 Django 會默認調用外部環境的 Python。解決方法:在虛擬環境里 pip install django。
OK,問題解決,一切正常。
附
一些我在配置時用到的命令,省得你去搜索:
1. 關閉 uWSGI:
killall -9 uwsgi killall -s HUP /var/www/uwsgi killall -s HUP /usr/local/bin/uwsgi
2. 列出端口占用情況:
netstat -lpnt
參考