一、如何在生產上部署Django?
Django的部署可以有很多方式,采用nginx+uwsgi的方式是其中比較常見的一種方式。
二、uwsgi介紹
uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換。
要注意 WSGI / uwsgi / uWSGI 這三個概念的區分。
- WSGI是一種Web服務器網關接口。它是一個Web服務器(如nginx,uWSGI等服務器)與web應用(如用Flask框架寫的程序)通信的一種規范。
- uwsgi是一種線路協議而不是通信協議,在此常用於在uWSGI服務器與其他網絡服務器的數據通信。
- 而uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。
- uwsgi協議是一個uWSGI服務器自有的協議,它用於定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型描述,它與WSGI相比是兩樣東西。
uwsgi性能非常高
uWSGI的主要特點如下
- 超快的性能
- 低內存占用(實測為apache2的mod_wsgi的一半左右)
- 多app管理(終於不用冥思苦想下個app用哪個端口比較好了-.-)
- 詳盡的日志功能(可以用來分析app性能和瓶頸)
- 高度可定制(內存大小限制,服務一定次數后重啟等)
If you are searching for a simple wsgi-only server, uWSGI is not for you, but if you are building a real (production-ready) app that need to be rock-solid, fast and easy to distribute/optimize for various load-average, you will pathetically and morbidly fall in love (we hope) with uWSGI.
三、Django + Uwsgi + Nginx 生產部署
1、准備環境
a、需要linux服務器一台
[root@web01 ~]# cat /etc/redhat-release CentOS release 6.6 (Final) [root@web01 ~]# uname -r 2.6.32-504.el6.x86_64
b、在服務器上面安裝好Python和Django
1、安裝setuptools
[root@django tools]# yum install pcre pcre-devel openssl openssl-devel zlib bzip2-devel -y [root@django tools]# ll -rw-r--r-- 1 root root 641502 3月 2 18:50 setuptools-19.6.tar.gz [root@django tools]# tar xf setuptools-19.6 [root@django tools]# cd setuptools-19.6 [root@django tools]#python setup.py install [root@django tools]#cd ..
################################################################## #nginx模塊 pcre pcre-devel #perl語言兼容正則表達式,用來做Nginx的HTTP Rewrite 模塊 bzip2-devel ·#提供壓縮功能 openssl openssl-devel #https加密模塊
###################################################################
zlib #在編譯python3的時候,加載setuptools的時候會報錯,所以這里提前處理啦!
2、安裝pip
[root@django tools]# ll -rw-r--r-- 1 root root 1197370 3月 2 13:30 pip-9.0.1.tar.gz [root@django tools]# tar xf pip-9.0.1.tar.gz [root@django tools]# cd pip-9.0.1 [root@django pip-9.0.1]# python setup.py install [root@django pip-9.0.1]# cd .. #配置環境變量: [root@django bin]# vi /etc/profile export PATH="/usr/local/python3/bin:$PATH" [root@django bin]# tail -1 /etc/profile export PATH="/usr/local/python3/bin:$PATH" [root@django bin]# source /etc/profile #查看幫助 [root@django bin]# pip3 或 pip
3、安裝sqlite3
方法一:
yum install sqlite-devel 或
方法二: 軟件下載官網:http://www.sqlite.org [root@django tools]# ll -rw-r--r-- 1 root root 2515143 3月 2 13:33 sqlite-autoconf-3170000.tar.gz [root@django tools]# tar xf sqlite-autoconf-3170000.tar.gz [root@django tools]# cd sqlite-autoconf-3170000 [root@django tools]# ./configure [root@django tools]#make && make install
4、安裝Python3
方法一:
升級為python3.5版本步驟 root@template ~]# cd /home/oldboy/tools/ #下載python-3.5.2 [root@template tools]# wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgz [root@template tools]# ll 總用量 20104 -rw-r--r-- 1 root root 20566643 6月 26 05:47 Python-3.5.2.tgz #解壓到下載目錄 [root@template tools]# tar zxvf Python-3.5.2.tgz #進入解壓后的文件夾 [root@template tools]# cd Python-3.5.2 #在編譯前先在/usr/local建一個文件夾python3(作為python的安裝路徑,以免覆蓋老的版本) [root@template Python-3.5.2]# mkdir /usr/local/python3 #開始編譯安裝 [root@template Python-3.5.2]# ./configure --prefix=/usr/local/python3 [root@template Python-3.5.2]# make && make install 此時沒有覆蓋老版本,再將原來/usr/bin/python鏈接改為別的名字 [root@template Python-3.5.2]# mv /usr/bin/python /usr/bin/python_old #再建立新版本python的軟鏈接 [root@template Python-3.5.2]# ln -s /usr/local/python3/bin/python3 /usr/bin/python #就會顯示出python的新版本信息 [root@template Python-3.5.2]# python Python 3.5.2 (default, Aug 2 2016, 11:35:06) [GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> exit() #<----退出python PS:如果不建立新安裝路徑python3,而是直接默認安裝,則安裝后的新python應該會覆蓋linux下自帶的老版本。當然如果還想保留原來的版本,那么這種方法最好不過了。 注意事項: 這種方法雖然能安裝成功,但會導致yum不能正常使用。 解決方法: [root@template tools]# cp /usr/bin/yum /usr/bin/yum.backup_2016-08-02 修改第一行參數 vi /usr/bin/yum 把 #!/usr/bin/python 修改為:/usr/bin/python_old 或 把 #!/usr/bin/python 修改為:/usr/bin/python2.6 #查看版本 [root@template Python-3.5.2]# python --version Python 3.5.2
#查看安裝路徑(可以省略這步)
[root@web01 ~]# python
Python 3.5.2 (default, May 27 2017, 18:39:42)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.path)
['', '/usr/local/python3/lib/python35.zip', '/usr/local/python3/lib/python3.5', '/usr/local/python3/lib/python3.5/plat-linux', '/usr/local/python3/lib/python3.5/lib-dynload', '/usr/local/python3/lib/python3.5/site-packages']
>>> exit()
5.安裝Django
方式一:用pip3安裝
pip3 install django
升級方法:
pip3 install django --upgrade
啟動django項目命令(備注:其它settings連接數據庫方法跟window一樣的)
#& 表示后台啟動 python manage.py runserver 0.0.0.0:80 &
6、安裝PyMysql (選裝,具體看你的項目連接方式)
pip3 install PyMySQL
#檢查模塊是否安裝成功
[root@web01 ~]# python
Python 3.5.2 (default, May 27 2017, 18:39:42)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymysql
>>>
>>> exit()
c、uwsgi
# 安裝 uwsgi [root@localhost teacher]# pip3 install uwsgi
測試uwsgi
[root@web01 nulige]# cd /home/nulige [root@web01 nulige]# mkdir -p uwsgi_test [root@web01 nulige]# cd uwsgi_test/
#測試文件
[root@web01 uwsgi_test]# vi test.py def application(env, start_response): start_response('200 OK', [('Content-Type','text/html')]) return [b"Hello World"] # python3 #return ["Hello World"] # python2
啟動uwsgi
[root@web01 uwsgi_test]# uwsgi --http :8000 --wsgi-file test.py *** Starting uWSGI 2.0.15 (64bit) on [Sat May 27 19:12:58 2017] *** compiled with version: 4.4.7 20120313 (Red Hat 4.4.7-11) on 27 May 2017 18:48:50 os: Linux-2.6.32-504.el6.x86_64 #1 SMP Wed Oct 15 04:27:16 UTC 2014 nodename: web01 machine: x86_64 clock source: unix pcre jit disabled detected number of CPU cores: 1 current working directory: /home/nulige/uwsgi_test detected binary path: /usr/local/python3/bin/uwsgi uWSGI running as root, you can use --uid/--gid/--chroot options *** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** *** WARNING: you are running uWSGI without its master process manager *** your processes number limit is 14719 your memory page size is 4096 bytes detected max file descriptor number: 1024 lock engine: pthread robust mutexes thunder lock: disabled (you can enable it with --thunder-lock) uWSGI http bound on :8000 fd 4 spawned uWSGI http 1 (pid: 17972) uwsgi socket 0 bound to TCP address 127.0.0.1:38831 (port auto-assigned) fd 3 Python version: 3.5.2 (default, May 27 2017, 18:39:42) [GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] *** Python threads support is disabled. You can enable it with --enable-threads *** Python main interpreter initialized at 0x1ed4a90 your server socket listen backlog is limited to 100 connections your mercy for graceful operations on workers is 60 seconds mapped 72768 bytes (71 KB) for 1 cores *** Operational MODE: single process *** WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x1ed4a90 pid: 17970 (default app) *** uWSGI is running in multiple interpreter mode *** spawned uWSGI worker 1 (and the only) (pid: 17970, cores: 1)
查看啟動端口
[root@web01 ~]# ps -ef|grep uwsgi root 17970 1000 0 19:12 pts/0 00:00:00 uwsgi --http :8000 --wsgi-file test.py root 17972 17970 0 19:12 pts/0 00:00:00 uwsgi --http :8000 --wsgi-file test.py root 17996 17973 0 19:14 pts/1 00:00:00 grep uwsgi
在瀏覽器中,通過ip+端口號進行訪問
根據項目進行配置
# 啟動 uwsgi **進入項目目錄** **使用uwsgi啟動前確保無代碼問題導致通過runserver可以正常啟動起來** uwsgi --http 192.168.31.123:8080 --file teacher/wsgi.py --static-map=/static=static #測試啟動 # 解釋 --http 這個就和runserver一樣指定IP 端口 --file 這個文件就里有一個反射,如果你在調用他的時候沒有指定Web Server就使用默認的 -- static 做一個映射,指定靜態文件
2、生產環境配置
Nginx + uWSGI + Djangos配置方法:
# uwsig使用配置文件啟動 [uwsgi] # 項目目錄 chdir=/opt/project_teacher/teacher/ # 指定項目的application module=teacher.wsgi:application # 指定sock的文件路徑 socket=/opt/project_teacher/script/uwsgi.sock # 進程個數 workers=5 pidfile=/opt/project_teacher/script/uwsgi.pid # 指定IP端口 http=192.168.31.123:8080 # 指定靜態文件 static-map=/static=/opt/test_project/teacher/static # 啟動uwsgi的用戶名和用戶組 uid=root gid=root # 啟用主進程 master=true # 自動移除unix Socket和pid文件當服務停止的時候 vacuum=true # 序列化接受的內容,如果可能的話 thunder-lock=true # 啟用線程 enable-threads=true # 設置自中斷時間 harakiri=30 # 設置緩沖 post-buffering=4096 # 設置日志目錄 daemonize=/opt/project_teacher/script/uwsgi.log
# uwsig常用命令
# 通過配置文件啟動 uwsgi --ini uwsgi.ini # 會生成兩個文件 PID文件 他是標識這個程序所處的狀態 SOCK文件 他是用來和其他程序通信的 # 停止uwsgi uwsgi --stop uwsgi.pid # 重載配置 uwsgi --reload uwsgi.ini
d、nginx
#先換成國內yum源
#以CentOS6.x 系統為例 1、備份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2、更換成國內源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo 3、之后運行yum makecache生成緩存
# 安裝nginx
yum -y install nginx
# Nginx添加配置文件
#先進入到配置文件:
vi /etc/nginx/conf.d/ #編輯配置文件 server { # 這個server標識我要配置了 listen 80; # 我要監聽那個端口 server_name 10.129.205.183 ; # 你訪問的路徑前面的url名稱 access_log /var/log/nginx/access.log main; # Nginx日志配置 charset utf-8; # Nginx編碼 gzip on; # 啟用壓縮,這個的作用就是給用戶一個網頁,比如3M壓縮后1M這樣傳輸速度就會提高很多 gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream; # 支持壓縮的類型 error_page 404 /404.html; # 錯誤頁面 error_page 500 502 503 504 /50x.html; # 錯誤頁面 # 指定項目路徑uwsgi location / { # 這個location就和咱們Django的url(r'^admin/', admin.site.urls), include uwsgi_params; # 導入一個Nginx模塊他是用來和uWSGI進行通訊的 uwsgi_connect_timeout 30; # 設置連接uWSGI超時時間 uwsgi_pass unix:/opt/project_teacher/script/uwsgi.sock; # 指定uwsgi的sock文件所有動態請求就會直接丟給他 } # 指定靜態文件路徑 location /static/ { alias /opt/project_teacher/teacher/static/; index index.html index.htm; } }
# 啟動Nginx通過Nginx訪問
/etc/init.d/nginx start /etc/init.d/nginx stop # 這里有個命令configtest,Nginx配置是重啟生效的,如果你修改完了,不知道對不對又擔心影響其他人可以使用它測試 /etc/init.d/nginx configtest # 如果是生產環境的話Nginx正在運行,就不要直接stop start 或者 restart 直接reload就行了 # 對線上影響最低(生產環境用的方法) /etc/init.d/nginx reload
e、Django Admin靜態文件配置
有一個小bug:
# 解決Django靜態配置文件丟失
問題原因: 是因為admin所需的js,css等靜態文件都在django的安裝目錄內,但是我們並沒有配置指向Django的配置文件。 解決辦法: 我們可以通過配置 STATIC_ROOT = os.path.join(BASE_DIR, "static_all")來指定靜態文件的默認家目錄是那里,然后把項目里所有的靜態文件都收集起來放到這個目錄下面。 收集命令: python3 manage.py collectstatic --noinput 修改Nginx 指定靜態路徑 alias /opt/test_project/teacher/static_all/;
#參數優化
首先參考下官網的 things to know : http://uwsgi-docs.readthedocs.org/en/latest/ThingsToKnow.html
我這邊最終啟動的命令如下:
uwsgi --socket 127.0.0.1:9090 -p 16 -l 8192 -M -R 100000 -z30 -L --wsgi-file app.py --max-apps 65535 --stats 127.0.0.1:1717 --post-buffering 100M --cpu affinity --buffer-size 65535 --daemonize /tmp/uwsgi --pidfile /tmp/uwsgi.pid --memory-report --threads 16