q2l
目錄
- 0x0 了解uWSGI*
- 0x1 部署uWSGI
- 0x2 了解NGINX
- 0x3 部署NGINX
- 0x4 NGINX和uWSGI建立連接配接
- Reference
可能有的同學對UWSGI比較陌生,更多是知道NGINX,但是我們的伺服器一開始的時候是先使用了uWSGI,後來才加上NGINX的。
uWSGI,是一個對WSGI協定的實作的應用,是以我們先來了解一下什麼是WSGI。
WSGI,Web Server Gateway Interface,也叫做the Python Web Server Gateway Interface,顯然是為Python所準備的web伺服器網關接口,作用是在協定之間進行轉換。目前很多架構都自帶了uWSGI的實作,如Flash、Django、webPy等,但是自帶的實作性能不敢恭維,多用作測試,釋出的話需要自己重新配置。
簡單點說,WSGI就是web伺服器和web應用之間的橋梁:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmL0QHM5YDMvVGMzo2cxY3ZzFnd4Y2Zxk3ZslkW4M1NwAzLcV2ZyFGbvwlbj5yZtlWYul2cuETY2R3Lc9CX6MHc0RHaiojIsJye.jpg)
其作用還可以用一副漫畫說明:
WSGI的作用此時應該已經了解了,總結一下:
- WSGI有兩方:“伺服器”或“網關”一方,以及“應用程式”或“應用架構”一方。服務方調用應用方,提供環境資訊,以及一個回調函數(提供給應用程式用來将消息頭傳遞給伺服器方),并接收Web内容作為傳回值。
- 所謂的 WSGI中間件同時實作了API的兩方,是以可以在WSGI服務和WSGI應用之間起調解作用:從WSGI伺服器的角度來說,中間件扮演應用程式;而從應用程式的角度來說,中間件扮演伺服器。
- “中間件”元件可以執行以下功能:
- 重寫環境變量後,根據目标URL,将請求消息路由到不同的應用對象。
- 允許在一個程序中同時運作多個應用程式或應用架構。
- 負載均衡和遠端處理,通過在網絡上轉發請求和響應消息。
- 進行内容後處理,例如應用XSLT樣式表。
差不多說完WSGI,接下來引入一下uwsgi,可能這時候有人迷惑了,一下大寫一下小寫,實際上這兩個是不同的:uwsgi與WSGI一樣是一種通信協定,是uWSGI伺服器的獨占協定,用于定義傳輸資訊的類型(type of information),每一個uwsgi packet前4byte為傳輸資訊類型的描述,與WSGI協定是兩種東西,據說該協定是fcgi協定的10倍快。我們的主角uWSGI是一個web伺服器,實作了WSGI協定、uwsgi協定、http協定等。
uWSGI的部署非常簡單,直接在python環境下安裝即可:
pip install uwsgi
建立 test.py:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"]
運作uWSGI:
uwsgi --http :8001 --wsgi-file test.py
此時在 http://127.0.0.1:8001 應該已經有Hello World的輸出了,說明安裝成功。
uWSGI可以配置多程序多線程,這個在後面一起講。
其實一開始的時候,我們并不想部署NGINX,覺得直接用python的runserver+uWSGI跑足以,但是随着通路數量的增多,甚至我們組内的測試使用都會出現卡頓,這時我們覺得是應該學習一下了。
NGINX大家非常熟悉,但是對于更多JAVA後端的同學來說,APACHE應該是早有耳聞,APACHE和NGINX一樣是一種WEB伺服器,找到一張對比圖:
web服務功能 | NGINX | APACHE |
---|---|---|
方向代理 | 支援反向代理 | 好 |
Rewrite | 非常好 | |
fastCHI(網關接口) | 差 | |
熱部署 | 支援 | 不支援 |
系統壓力比較 | 很小 | 小 |
穩定性 | ||
安全性 | 一般 | |
靜态檔案處理 | ||
動态檔案處理 | ||
虛拟主機 | ||
記憶體消耗 | 非常小 | 很大 |
擴充資料 | 很少 | 非常多 |
兩者最核心的差別在于:
APACHE是同步多程序模型,一個連接配接對應一個程序,而NGINX是異步的,多個連接配接(上萬級别)可以對應一個程序。
是以一般來說,需要性能的WEB服務,大多使用NGINX,而需要穩定的更考慮APACHE,後者的各種功能子產品實作都比前者更加完善,配置更多。更加通用的方案是:前端NGINX抗并發,後端APACHE叢集,組成配合。
像是淘寶、支付寶、迅雷、新浪部落格等高并發的網站,都是用的是NGINX作為WEB伺服器。
考慮到我們的實際情況:
- 伺服器配置低:2C4G
- 靜态資源請求多:加載登陸界面和個别界面需要加載背景圖檔
- 需要頻繁啟動:網站版本疊代更新快
- 對同時連接配接數量要求高
- 可能需要反向代理
根據上面幾個特點,我們選擇了NGINX作為web伺服器。
接下來以我們運作CentOS的aliyun的2C4G的ECS伺服器為環境進行介紹。
首先,需要安裝NGINX,在CentOS下直接
yum install -y nginx
即可。
NGINX的配置需要在
/etc/nginx/nginx.conf
中修改,這個等下一起說。
uWSGI對于動态資源的處理很好,NGINX對于靜态資源的處理很好,是以通常django應用會結合NGINX和uWSGI一起作為web服務端。NGINX抗高并發,接收所有的請求,對于靜态資源的請求直接自身處理,對于動态資源的請求再轉發給uWSGI處理。接下來詳述我們的NGINX配置:
user root; # 可能要給予NGINX程序以root執行的權限才能對socket之類的檔案進行改寫
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
# mysite_nginx.conf
events {
worker_connections 1024; ## Default: 1024
}
http
{
server_tokens off;
autoindex off;
access_log off;
include mime.types;
default_type application/octet-stream;
proxy_hide_header X-Powered-By;
# 開啟gzip壓縮更快傳輸靜态資源
gzip on;
gzip_min_length 1k; # 對請求的靜态資源的大小設定門檻值,小于1k的資源經過壓縮反而會變大
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
include /etc/nginx/mime.types;
# the upstream component nginx needs to connect to
# 在這裡 NGINX 負責連接配接的web服務端是django應用程式,是NGXIN的上遊upstream
upstream django {
# for a file socket
# 這裡的server使用的是sock檔案,代替使用伺服器端口
server unix:///your/path/to/backend.sock;
# server 127.0.0.1:8001; # for a web port socket (we'll use this first, but replace it later)
}
# configuration of the server
server {
# the port your site will be served on
listen 80;
listen [::]:80;
# the domain name it will serve for
server_name your.ip.address; # substitute your machine's IP address or FQDN
charset utf_8_sig; # utf_8_sig 對中文的支援最好
include /etc/nginx/default.d/*.conf;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /your/path/to/media; # your Django project's media files - amend as required
}
location /static {
# 注意這裡我們嘗試使用root來定義,請求的靜态資源是直接拼接在下面的路徑下的,使用root表示所在的根目錄,是以如果網站的靜态資源都存在于/frontend/static中,下面的root路徑應該寫/frontend檔案夾的路徑而不是/static的路徑,比如我們的登陸界面北京的連接配接為:http://website/static/img/bgd.cc940dc6.png,就是将/img/bgd.cc940dc6.png拼接到root後面進行請求
# 當然你也可以用上面的alias的别名方式,直接替換請求的路徑
root /your/path/to/static‘s/parent; # your Django project's static files - amend as required
# 另一種寫法
# alias /your/path/to/static;
break;
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django; # 設定将除靜态資源外的請求發送給誰,這裡的django是上面的upstream的django
uwsgi_read_timeout 360s; # 設定逾時
uwsgi_send_timeout 360s; # 設定逾時
include /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
index index.html;
}
}
在 upstream django中,我們的server使用了一個套接字,實際上server還可以是伺服器的一個端口,如
:8001
端口,但是套接字socket是直接給予Unix的底層實作的,套接字檔案的讀寫速度非常快,當并發高時,Unix Socket比TCP port要快一些。但是如果要使用複雜均衡,則必須要使用TCP port。
接下來設定負責處理動态資源請求的後端uWSGI,該檔案名為uwsgi.ini,存放在django項目檔案夾内:
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /your/path/to/backend
# Django's wsgi file
# module = backend.wsgi
env = DJANGO_SETTINGS_MODULE=backend.settings
# the virtualenv (full path)
home = /your/path/to/venv
# where wsgi file locate, normaly in app/wsgi.py
wsgi-file = app/wsgi.py
# where the log file output
daemonize = nohup.out
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 10
# the socket (use the full path to be safe
socket = /your/path/to/backend.sock
# ... with appropriate permissions - may be needed
chmod-socket = 664
# clear environment on exit
vacuum = true
harakiri=360 # harakiri(伺服器響應時間)逾時伺服器停止計算
http-timeout=360 # 前後端斷開連結時間,伺服器繼續計算,單獨uwsgi時使用
socket-timeout=360 # 前後端斷開連結時間,伺服器繼續計算,配合nginx時使用
# python-autoreload=1
# buffer-size=1024
max-requests = 1000
接下來看app應用内的wsgi的配置,該檔案存放在django項目的app應用檔案夾内:
"""
WSGI config for backend project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_wsgi_application()
- Python uWSGI 安裝配置
- uWSGI詳解
- uwsgi、wsgi和nginx的差別和關系
- Official | uwsgi WSGI quickStart
- Official | NGINX
- Python網絡程式設計之wsgi、uwsgi概念及作用