開發(fā)人員
盡管如此,由于它起初是一個內(nèi)部的,閉源的項目,一直有另外一個非常重要的目標(biāo):Django應(yīng)該容易部署,并且應(yīng)該使得用
有限的資源服務(wù)巨大的流量可行
這個目標(biāo)的動機(jī)在你查看Django的背景時就很顯然了:在堪薩斯的一份很小的,家族保有的報紙很難負(fù)擔(dān)頂級的服務(wù)器硬件,
所以Django最初的開發(fā)人員關(guān)心從有限的資源擠出最佳的性能,確實,Django的開發(fā)人員作為他們自己系統(tǒng)的管理員幾年時
間了--沒有需要專門管理的足夠的硬件--即使他們的站點一天處理上千萬的點擊
Django變成開源項目后,由于不同的原因?qū)τ谛阅艿年P(guān)注和使開發(fā)變輕松就變得非常重要:有癖好的開發(fā)者,想使用Django的
個人對于他們找到每月只要花費$10即可搭建小到中型流量的站點感到非常高興
但是能夠應(yīng)付小的性能只是成功的一半,Django也需要提高性能來滿足大公司和企業(yè),這里Django采用了通常在LAMP類似的
web堆棧的哲學(xué),它通常稱為"不分享任何東西"
LAMP?
首字母縮寫LAMP最初用來描述一些用來驅(qū)動許多網(wǎng)站的流行的開源軟件:
Linux(操作系統(tǒng))
Apache(web服務(wù)器)
MySQL(數(shù)據(jù)庫)
PHP(編程語言)
但是其他時候這個首字母縮寫更多的表示這些類型的開源軟件堆棧的哲學(xué)而不是特殊的堆棧,所以當(dāng)Django使用Python并且
數(shù)據(jù)庫不可知時,通過LAMP堆棧證明的該哲學(xué)滲透了Django的部署心理
有些(大部分很滑稽)對于創(chuàng)造類似的首字母縮寫來描述Django的技術(shù)堆棧的嘗試,你的作者們喜歡PAID(PostgreSQL,Apache
Internet和Django)或者LAPD(Linux,Apache,PostgreSQL和Django)
"不分享任何東西"
作為它的核心,"不分享任何東西"的哲學(xué)只是對整個軟件堆棧松耦合的應(yīng)用,這個架構(gòu)引起了對當(dāng)前什么是主流架構(gòu)的直接
響應(yīng):包裝語言的單獨的web應(yīng)用服務(wù)器,數(shù)據(jù)庫,web服務(wù)器--甚至部分操作系統(tǒng)--到一個單獨的處理(例如Java)
當(dāng)?shù)搅诵枰炜s性的時刻,這可能是個主要的問題,幾乎不能在多個不同的物理機(jī)器上分隔單獨的處理工作,所以單獨的程
序需要強(qiáng)有力的服務(wù)器,當(dāng)然,這些服務(wù)器價值上萬甚至幾十萬美金,這讓高性能的網(wǎng)站與缺少現(xiàn)金的個人和小公司無緣
盡管如此,LAMP社區(qū)注意到如果你把web堆棧的每個部分分解成單獨的組件,你可以輕松的以便宜的服務(wù)器開始,并且隨著你
逐漸成長來簡單的添加更便宜的服務(wù)器,如果你的$3,000的數(shù)據(jù)庫服務(wù)器不能處理負(fù)載,你簡單的購買第二個(或者第三個,
或者第四個)直到它可以,如果你需要更多存儲能力,你可以添加一臺NFS服務(wù)器
但是,為了讓它工作,web程序必須停止假設(shè)同一服務(wù)器將處理每個請求--或者甚至一個單獨請求的每個部分,在高伸縮性的
LAMP(以及Django)部署中,多達(dá)一打的服務(wù)器可能與一個單獨的頁面有關(guān)!這點的反響是眾多的,但是本質(zhì)上為這幾點:
1,狀態(tài)不能在本地存儲,換句話說,在多個請求間可得到的任何數(shù)據(jù)必須存儲在某種類型的持久化存儲中,如數(shù)據(jù)庫或集中
緩存
2,軟件不能假設(shè)資源是本地的,例如,web平臺不能假設(shè)數(shù)據(jù)庫運(yùn)行于同一服務(wù)器,它必須能夠連接遠(yuǎn)程數(shù)據(jù)庫服務(wù)器
3,堆棧的每一部分必須很容易移動或者復(fù)制:如果Apache出于某種原因不能為給定的部署工作,你應(yīng)該可以以最小的忙亂來
用另外的服務(wù)器替換它
或者,在硬件級別:如果web服務(wù)器出故障了,你應(yīng)該可以以最小的停工期用另外一個物理盒子替換它,記住,整個哲學(xué)基于
在便宜的日用品硬件上部署,故障是預(yù)期的
你可能想到,Django或多或少透明的處理這個--Django沒有哪部分違反了這些原則--但是了解該哲學(xué)對于到了追求伸縮性時
會有幫助
但是它工作嗎?
該哲學(xué)可能對于在紙上(或者在你的屏幕上)看起來很好,但是它真的工作嗎?
好了,讓我們看看一個不完整的一些基于該架構(gòu)開展它們的業(yè)務(wù)的公司的列表,你可能認(rèn)得一些名字:
Amazon
BLogger
Craigslist
LiveJournal
Slashdot
Wikipedia
Yahoo
YouTube
為了從當(dāng)Harry遇上Sally...解釋著名的場景:"我們將擁有他們有的東西!"
個人喜好的注意
在我們進(jìn)入細(xì)節(jié)之前,一個快速的周邊
開源由于所謂的"宗教戰(zhàn)爭"而著名:許多(數(shù)字的)墨水灑在關(guān)于文本編輯器(emacs vs. vi),操作系統(tǒng)(Linux vs. Windows v
s. MacOS),數(shù)據(jù)庫引擎(MySQL vs. PostgreSQL),以及--當(dāng)然--編程語言的爭論上
我們嘗試遠(yuǎn)離這些戰(zhàn)爭,我們沒有足夠的時間
盡管如此,當(dāng)?shù)搅瞬渴餌jango時有一些選擇,并且我們經(jīng)常尋求我們的偏愛,既然陳述這些偏好接近于這些戰(zhàn)爭中煽動一個
保留條款一樣危險,我們通常都避免了,但是出于完整性的原因,我們將在這里陳述它們,我們選擇:
Linux--明確的為Ubuntu--作為我們的操作系統(tǒng)
Apache和mod_python作為web服務(wù)器
PostgreSQL作為數(shù)據(jù)庫服務(wù)器
當(dāng)然,我們可以指出許多做出其他選擇并工作的很好的Django用戶
怎樣同Apache和mod_python使用Django
Apache和mod_python目前是在產(chǎn)品服務(wù)器上使用Django的最健壯的裝備
mod_python是在Apache中嵌入Python的Apache插件,它當(dāng)服務(wù)器運(yùn)行時載入Python代碼到內(nèi)存中,代碼在一個Apache處理的
周期一直駐留在內(nèi)存中,這帶來比其他服務(wù)器安排更好的性能
Django需要Apache2.x和mod_python3.x,并且你應(yīng)該使用Apache的prefork MPM,而不是worker MPM
注意
配置Apache超出了本書的內(nèi)容,所以我們將簡單的提到需要的細(xì)節(jié),幸運(yùn)的是,如果你需要學(xué)習(xí)更多關(guān)于Apache的知識,有
大量的資源可以得到,其中我們喜歡的一些為:
免費的在線apache文檔
Peter Wainwrite(Apress)的Pro Apache
Ben Laurie和Peter Laurie(O'Reilly)的Apache:The Definitive Guide
基本配置
為了用mod_python配置Django,首先確認(rèn)你安裝了Apache并激活了mod_python模塊,這通常意味著在你的Apache配置里有一
個LoadModule指示,這通常看起來像這樣:
- LoadModule python_module /usr/lib/apache2/modules/mod_python.so
然后編輯你的Apache配置并添加下面的東西:
- <Location "/">
- SetHandler python-program
- PythonHandler django.core.handlers.modpython
- SetEnv DJANGO_SETTINGS_MODULE mysite.settings
- PythonDebug On
- </Location>
確認(rèn)為你的站點使用合適的DJANGO_SETTINGS_MODULE來替換mysite.settings
這告訴Apache:"通過使用Django的mod_python handler來為任何在'/'下的URL使用mod_python",它傳遞DJANGO_SETTINGS_M
ODULE的值來讓mod_python知道使用哪個settings
注意我們使用Location指示,而不是Directory指示,后者用來指出你的文件系統(tǒng)的位置,而Location指出一個網(wǎng)站的URL結(jié)
構(gòu)的位置,Directory在這里將沒有意義
而且如果你手動更改了你的PYTHONPATH來放置你的Django項目,你將需要告訴mod_python:
PythonPath "['/path/to/project'] + sys.path"
你也可以為了性能而添加例如PythonAutoReload Off等指示,參考mod_python documentation
來得到完整的選項列表
注意你應(yīng)該在產(chǎn)品服務(wù)器中設(shè)置PythonDebug Off,如果你保持PythonDebug On,當(dāng)mod_python出現(xiàn)問題時你的用戶將看到丑
陋的(并且暴露的)Python堆棧信息
重啟Apache,Django將服務(wù)你的站點(或者你將該指示放在VirtualHost塊里則時虛擬主機(jī))的任何請求
注意
如果你在一個子目錄部署Django--即,比"/"更深的地方--Django不會修改你的URL模式的URL前綴,這樣,如果你的Apache
這樣配置:
- <Location "/mysite/">
- SetHandler python-program
- PythonHandler django.core.handlers.modpython
- SetEnv DJANGO_SETTINGS_MODULE mysite.settings
- PythonDebug On
- </Location>
則你所有的URL模式將需要以"/mysite/"開始,出于這個原因我們通常建議在你的域名或者虛擬主機(jī)的根部署Django
在同一Apache實例的多個Django安裝
可以在同一Apache實例運(yùn)行多個Django安裝,只需像這樣使用VirtualHost:
- NameVirtualHost *
- <VirtualHost *>
- ServerName www.example.com
- # ...
- SetEnv DJANGO_SETTINGS_MODULE mysite.settings
- </VirtualHost>
- <VirtualHost *>
- ServerName www2.example.com
- # ...
- SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
- </VirtualHost>
如果你需要在同一VirtualHost放置兩個Django安裝,你將需要采用一個特殊的防范來保證mod_python的代碼緩存不會把事情
弄糟,使用PythonInterpreter指示來給不同的Location指示分別的interpreters:
- <VirtualHost *>
- ServerName www.example.com
- # ...
- <Location "/something">
- SetEnv DJANGO_SETTINGS_MODULE mysite.settings
- PythonInterpreter mysite
- </Location>
- <Location "/otherthing">
- SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
- PythonInterpreter mysite_other
- </Location>
- </VirtualHost>
只要它們在不同的兩個Location塊中,PythonInterpreter的值沒有關(guān)系
使用mod_python運(yùn)行開發(fā)服務(wù)器
由于mod_python緩存了載入的Python代碼,當(dāng)在mod_python部署Django站點時你將需要在每次你更改你的代碼時重啟Apache
這可能引起爭辯,所以這里是避免它的快速技巧:
只需添加MaxRequestsPerChild 1到你的配置文件來強(qiáng)迫Apache對每個請求重新載入每個東西,但是不要在產(chǎn)品服務(wù)器上做
這件事,否則我們將廢除你的Django特權(quán)
如果你是使用分散的print語句來調(diào)試的程序員,注意print語句在mod_python中沒有效果,它們不會期望中的在Apache日志
中出現(xiàn),如果你需要在mod_python設(shè)置中打印調(diào)試信息,你將可能想使用Python的標(biāo)準(zhǔn)日志包或者添加調(diào)試信息到你的頁面
的模板中
從同一Apache實例服務(wù)Django和media文件
Django本身不服務(wù)media文件,它把這項工作留給你選擇的Web服務(wù)器,我們建議使用單獨的Web服務(wù)器--即,不是運(yùn)行Django
的那個--來服務(wù)media,參考下面的伸縮性部分
但是,如果你沒有其他選擇而只能在Django的同一Apache VirtualHost上服務(wù)media文件,這里是為站點的特殊部分關(guān)閉mod_
python:
- <Location "/media/">
- SetHandler None
- </Location>
更改Location為你的media文件的根URL
你也可以使用LocationMatch來匹配正則表達(dá)式,例如,這在站點的根來建立Django但是顯示的在media子目錄和任何以.jpg,
.gif或.png結(jié)尾的URL禁止Django:
- <Location "/">
- SetHandler python-program
- PythonHandler django.core.handlers.modpython
- SetEnv DJANGO_SETTINGS_MODULE mysite.settings
- </Location>
- <Location "media">
- SetHandler None
- </Location>
- <LocationMatch "\.(jpg|gif|png)$">
- SetHandler None
- </LocationMatch>
錯誤處理
當(dāng)你使用Apache/mod_python時,錯誤將被Django捕獲--換句話說,它們不會傳播到Apache級別并且不會在Apache的error_lo
g中出現(xiàn)
例外是當(dāng)你的Django設(shè)置中有些東西真正的弄糟時,這種情況下,你將在你的瀏覽器中看到一個"內(nèi)部服務(wù)器錯誤"頁面并在
你的Apache的error_log文件里看到完整的堆棧信息,error_log堆棧信息分布在多行(是的,這很丑陋并且很難閱讀,但這是
mod_python做事情的方式)
如果你得到分割故障
有時候,當(dāng)你安裝Django時Apache出錯,當(dāng)這發(fā)生時,幾乎一直是與Django本身不相關(guān)的兩個原因中的一個:
1,可能是你的Python代碼正在import pyexpat模塊(用來解析XML),這可能與嵌入Apache的版本沖突
參看Expat導(dǎo)致Apache垮掉得到完整的信息
2,可能是因為你正在同一Apache實例中運(yùn)行mod_python和mod_php,并使用MySQL作為數(shù)據(jù)庫后端
有些情況下,這導(dǎo)致由于PHP和Python的MySQL后端的版本沖突產(chǎn)生的已知的mod_python問題
在mod_python FAQ條目有完整的信息
如果你對設(shè)置mod_python仍然有問題,一個好事情是讓一個空的沒有Django框架的mod_python站點工作,這是分離mod_pytho
n專有的問題的簡易的方式
讓mod_python工作詳細(xì)介紹了這點
下一步應(yīng)該是編輯你的測試代碼并添加你使用的Django專有的代碼的import--你的視圖,模型,URL配置,RSS配置等等,把
這些imports放在你的測試handler方法里并在瀏覽器里訪問你的測試URL,如果這導(dǎo)致失敗,你就能確認(rèn)是由于import Djan
go代碼導(dǎo)致的問題,逐漸減少imports的數(shù)量直到它停止出錯,這樣就找到了導(dǎo)致問題的特殊的模塊,如果有必要則深入到
模塊中并觀察它們的imports
怎樣同F(xiàn)astCGI使用Django
盡管在Apache和mod_python下的Django是最健壯的部署設(shè)置,許多人使用的是FastCGI是唯一的選項的共享主機(jī)
而且,在某些情況下,F(xiàn)astCGI允許比mod_python更好的安全和可能更佳的性能,對于小站點,F(xiàn)astCGI也比Apache更輕量
什么是FastCGI?
FastCGI是讓外部程序?qū)eb服務(wù)器服務(wù)頁面的有效的方式,Web服務(wù)器委派進(jìn)來的Web請求(通過socket)給FastCGI,F(xiàn)astCGI
則執(zhí)行代碼并傳遞應(yīng)答給Web服務(wù)器,Web服務(wù)器則依次將應(yīng)答返回給客戶端Web瀏覽器
像mod_python一樣,F(xiàn)astCGI允許代碼駐留在內(nèi)存中,這就允許零啟動時間來服務(wù)請求,不像mod_python,F(xiàn)astCGI進(jìn)程不在
Web服務(wù)器進(jìn)程里運(yùn)行,而是一個單獨的,持久的進(jìn)程
為什么在單獨的進(jìn)程里運(yùn)行代碼?
Apache里傳統(tǒng)的mod_*配置把不同的腳本語言(特別是PHP,Python和Perl)嵌入在你的Web服務(wù)器進(jìn)程空間里面,盡管這減少了
啟動時間--因為代碼不需要為每個請求讀硬盤--它是以內(nèi)存使用為代價的
每個Apache進(jìn)程得到Apache引擎的拷貝,包括Django不使用的Apache的所有特性,在另一方面,F(xiàn)astCGI進(jìn)程只擁有Python和
Django的內(nèi)存過度
由于FastCGI的本性,也可以以一個不同的用戶帳號運(yùn)行的進(jìn)程而不是Web服務(wù)器進(jìn)程,這在共享系統(tǒng)里是一個很好的安全好
處,因為這意味著你可以從其他用戶保護(hù)你的代碼
先決條件:flup
在你開始同Django使用FastCGI之前,你將需要安裝flup,這是用來處理FastCGI的Python庫,有些用戶報告了老版本flup的
頁面延遲,所以你可能想使用最新的SVN版本
運(yùn)行你的FastCGI服務(wù)器
FastCGI基于客戶端-服務(wù)器模型操作,在大部分情況下你將啟動你自己的FastCGI服務(wù)器進(jìn)程,當(dāng)服務(wù)器需要載入動態(tài)頁面時
你的Web服務(wù)器(Apache,lighttpd,或者其他的)只聯(lián)系你的Django-FastCGI進(jìn)程,由于后臺進(jìn)程已經(jīng)將代碼運(yùn)行在內(nèi)存中,
則可以快速的服務(wù)應(yīng)答
注意
如果你在一個共享主機(jī)系統(tǒng)上,你可能將被強(qiáng)迫使用Web服務(wù)器管理的FastCGI進(jìn)程,參考下面的使用Web服務(wù)器管理的進(jìn)程來
運(yùn)行Django來得到更多信息
Web服務(wù)器可以用兩種方式連接FastCGI服務(wù)器:它可以使用Unix域socket(在Win32系統(tǒng)上的"命名管道")或者使用TCP socket
你的選擇是一種偏好,由于權(quán)限問題TCP socket更簡單
為了啟動你的服務(wù)器,首先進(jìn)入你的項目的目錄(你的manage.py所在的地方),然后使用runfcgi選項運(yùn)行manage.py:
- ./manage.py runfcgi [options]
如果你指定help作為runfcgi后面唯一的選項,它將顯示所有可得到的選項的列表
你將需要指定socket或者h(yuǎn)ost和port,然后,當(dāng)你啟動你的Web服務(wù)器時,你將只需在啟動FastCGI服務(wù)器時在你指定的host/
port或者socket指出它
一些例子應(yīng)該可以幫助解釋這點
1,在一個TCP端口運(yùn)行一個threaded服務(wù)器:
- ./manage.py runfcgi method=threaded host=127.0.0.1 port=3033
2,在一個Unix域socket運(yùn)行一個preforked服務(wù)器:
- ./manage.py runfcgi method=prefork socket=/home/user/mysite
3,不用后臺化(背景化)進(jìn)程來運(yùn)行(利于調(diào)試):
- ./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock
停止FastCGI后臺進(jìn)程
如果你有一個進(jìn)程運(yùn)行在前臺,很容易停止它:簡單的輸入Ctrl-C將停止和退出FastCGI服務(wù)器,但是當(dāng)你處理后臺進(jìn)程時,
你將需要求諸于Unix kill命令
如果你指定pidfile選項到你的manage.py runfcgi,你可以像這樣殺掉運(yùn)行的FastCGI后臺進(jìn)程:
- kill `cat $PIDFILE`
這里$PIDFILE為你指定的pidfile
為了使在Unix上重啟你的FastCGI后臺進(jìn)程很容易,你可以使用這個小shell腳本:
- #!/bin/bash
- # Replace these three settings.
- PROJDIR="/home/user/myproject"
- PIDFILE="$PROJDIR/mysite.pid"
- SOCKET="$PROJDIR/mysite.sock"
- cd $PROJDIR
- if [ -f $PIDFILE ]; then
- kill `cat -- $PIDFILE`
- rm -f -- $PIDFILE
- fi
- exec /usr/bin/env - \
- PYTHONPATH="../python:.." \
- ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
Apache和FastCGI
為了同Apache和FastCGI使用Django,你將需要安裝和配置Apache,并讓mod_fastcgi安裝和激活,參考Apache和mod_fastcgi
文檔來得到指示
一旦你建立了這些東西,通過編輯httpd.conf(Apache配置)文件來將Apache指向你的Django FastCGI實例
你將需要做兩件事情:
1,使用FastCGIExternalServer指示來指定你的FastCGI服務(wù)器的位置
2,使用mod_rewrite來將URLs指向合適的FastCGI
指定FastCGI服務(wù)器的位置
FastCGIExternalServer指示告訴Apache怎樣找到你的FastCGI服務(wù)器
FastCGIExternalServer文檔解釋到,
你可以指定socket或者h(yuǎn)ost,這里是兩者的例子:
- # Connect to FastCGI via a socket / named pipe.
- FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
- # Connect to FastCGI via a TCP host/port.
- FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033
不管哪種情況,/home/user/public_html/mysite.fcgi事實上不需要存在,它只是Web服務(wù)器內(nèi)部使用的URL--一個表示對于
一個URL的哪個請求應(yīng)該通過FastCGI處理的鉤子(下一部分對此講解更多)
使用mod_rewrite將URLs指向FastCGI
第二步是告訴Apache對匹配某一模式的URLs使用FastCGI,為了做這個,使用mod_rewrite模塊并重寫URLs到mysite.fcgi(或
者你在FastCGIExternalServer指示里指定的任何東西,上面的部分解釋了)
在這個例子中,我們告訴Apache使用FastCGI來處理不表示文件系統(tǒng)中的文件和不以/media/開頭的任何請求,如果你在使用
Django的admin站點,這可能是最常見的情況:
- <VirtualHost 12.34.56.78>
- ServerName example.com
- DocumentRoot /home/user/public_html
- Alias /media /home/user/python/django/contrib/admin/media
- RewriteEngine On
- RewriteRule ^/(media.*)$ /$1 [QSA,L]
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
- </VirtualHost>
FastCGI和lighttpd
lighttpd是一個輕量的Web服務(wù)器,它通常用于服務(wù)靜態(tài)文件,它
天生支持FastCGI,這樣,如果你的站點沒有Apache專有的需求的話,它是服務(wù)靜態(tài)和動態(tài)頁面的好的選擇
確認(rèn)mod_fastcgi在你的模塊列表中,位于mod_rewrite和mod_access之后,但不再mod_accesslog之后,你可能將也想要mod_
alias來服務(wù)admin的media
添加下列內(nèi)容到你的lightpd配置文件:
- server.document-root = "/home/user/public_html"
- fastcgi.server = (
- "/mysite.fcgi" => (
- "main" => (
- # Use host / port instead of socket for TCP fastcgi
- # "host" => "127.0.0.1",
- # "port" => 3033,
- "socket" => "/home/user/mysite.sock",
- "check-local" => "disable",
- )
- ),
- )
- alias.url = (
- "/media/" => "/home/user/django/contrib/admin/media/",
- )
- url.rewrite-once = (
- "^(/media.*)$" => "$1",
- "^/favicon\.ico$" => "/media/favicon.ico",
- "^(/.*)$" => "/mysite.fcgi$1",
- )
在一個lighttpd實例上運(yùn)行多個Django站點
lighttpd讓你使用"有條件的配置"來允許對每個主機(jī)自定義配置,為了指定多個FastCGI站點,只需為每個站點添加有條件的
塊來包圍你的FastCGI配置:
- # If the hostname is 'www.example1.com'...
- $HTTP["host"] == "www.example1.com" {
- server.document-root = "/foo/site1"
- fastcgi.server = (
- ...
- )
- ...
- }
- # If the hostname is 'www.example2.com'...
- $HTTP["host"] == "www.example2.com" {
- server.document-root = "/foo/site2"
- fastcgi.server = (
- ...
- )
- ...
- }
你也可以通過在fastcgi.server指示里指定多個條目來在同一站點上運(yùn)行多個Django安裝,為每項添加一個FastCGI主機(jī)
在共享主機(jī)服務(wù)商上同Apache運(yùn)行Django
許多共享主機(jī)服務(wù)商不允許你運(yùn)行你自己的服務(wù)器后臺進(jìn)程后者編輯httpd.conf文件,這種情況下,仍然可以使用Web服務(wù)器
生成的進(jìn)程運(yùn)行Django
注意
如果你使用這部分解釋的Web服務(wù)器生成的進(jìn)程,你沒必要自己啟動FastCGI服務(wù)器,Apache將作為伸縮性需要而自己生成一
些進(jìn)程
在你的Web根目錄,添加下列內(nèi)容到一個叫.htaccess的文件:
- AddHandler fastcgi-script .fcgi
- RewriteEngine On
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
然后,創(chuàng)建一個告訴Apache怎樣生成你的FastCGI程序的小腳本,創(chuàng)建一個mysite.fcgi并把它放在你的Web目錄并確保它可
執(zhí)行:
- #!/usr/bin/python
- import sys, os
- # Add a custom Python path.
- sys.path.insert(0, "/home/user/python")
- # Switch to the directory of your project. (Optional.)
- # os.chdir("/home/user/myproject")
- # Set the DJANGO_SETTINGS_MODULE environment variable.
- os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
- from django.core.servers.fastcgi import runfastcgi
- runfastcgi(method="threaded", daemonize="false")
重啟生成的服務(wù)器
如果你在你的站點更改了任何Python代碼,你將需要告訴FastCGI代碼已經(jīng)更改,但是這種情況下沒有必要重啟Apache,而是
只需重新上傳mysite.fcgi--或者編輯該文件--這樣該文件的時間戳將改變,當(dāng)Apache發(fā)現(xiàn)該文件已經(jīng)更新,它將為你重啟你
的Django程序
如果你在Unix系統(tǒng)上可以訪問命令行shell,你可以通過使用touch命令簡單的達(dá)到這點:
- touch mysite.fcgi
提高伸縮性
既然你了解了怎樣讓Django運(yùn)行在一個單獨的服務(wù)器上,讓我們看看你怎樣提高一個Django安裝的伸縮性,這部分將通覽一
個站點怎樣從一個單獨的服務(wù)器到可以服務(wù)每小時幾百萬點擊率的高伸縮性的集群
但是,注意幾乎每個大型站點以不同的方式大很重要,所以提高伸縮性不是一個尺碼量天下的操作,下面的內(nèi)容應(yīng)該滿足顯
示一般的原則,我們將嘗試指出我們可以在哪里做出不同的選擇
首先,我們將做一個非常大的假設(shè)并額外談?wù)勗贏pache和mod_python下提高伸縮性,盡管我們許多成功的中到大型FastCGI部
署,我們簡單的更熟悉Apache
單獨的服務(wù)器
大部分站點以運(yùn)行在一個單獨的服務(wù)器上開始,使用看起來像這樣的架構(gòu):

這對小到中等的站點工作的很好,并且十分便宜--你可以花費少于$3,000設(shè)計來將Django放置在一個單獨的服務(wù)器
盡管如此,當(dāng)流量增加后你將很快進(jìn)入對不同的軟件進(jìn)行資源爭奪的處境,數(shù)據(jù)庫服務(wù)器和web服務(wù)器喜歡將整個服務(wù)器歸屬
它們自己來使用,所以當(dāng)在同一服務(wù)器上運(yùn)行時它們經(jīng)常為獨占同一資源(RAM,CPU)而"打架"
這可以通過將數(shù)據(jù)庫服務(wù)器移動到第二臺機(jī)器上來輕松解決
把數(shù)據(jù)庫服務(wù)器分離開
分離數(shù)據(jù)庫服務(wù)器
對Django而言,這非常簡單:你將簡單的需要更改DATABASE_HOST設(shè)置為你的數(shù)據(jù)庫服務(wù)器的IP或DNS,如果可以的話使用IP可
能是個好主意,依賴于DNS來連接你的web和數(shù)據(jù)庫服務(wù)器可能是個大問題
通過將數(shù)據(jù)庫服務(wù)器分離,我們的架構(gòu)現(xiàn)在看起來像這樣:

這里我們開始進(jìn)入通常所謂的N層架構(gòu),不要被專業(yè)術(shù)語嚇倒,它只是指web堆棧分離到不同的物理機(jī)器的不同的層
這樣的話如果你期望需要增加超過一個單獨的數(shù)據(jù)庫服務(wù)器,現(xiàn)在就開始考慮連接池和/或數(shù)據(jù)庫復(fù)制可能是個好主意,本書
幾乎沒有足夠的空間來討論這些話題--不幸的是--所以你將需要參考你的數(shù)據(jù)庫文檔和/或社區(qū)來得到更多的信息
單獨的media服務(wù)器
對于單獨的服務(wù)器設(shè)置我們?nèi)匀皇S幸粋大問題:從處理動態(tài)內(nèi)容的同一盒子服務(wù)media
這兩個活動在不同的環(huán)境下處理最好,把它們糅合在一個盒子里你將不會把任何一個處理得很好,所以下一步是把media隔離
開來--即,不是Django視圖生成的任何東西--到一個專門的服務(wù)器:
[img]http://media.djangobook.com/content/chapter21/scaling-3.png[img]
理想情況下,這個media服務(wù)器應(yīng)該運(yùn)行一個單獨的優(yōu)化來發(fā)布靜態(tài)media的web服務(wù)器
lighttpd和tux在這里都是很好的選擇,但是一個重量級的單獨Apache也可以工作
對于靜態(tài)內(nèi)容很多的站點--照片,視頻等等--移動到一個單獨的media服務(wù)器更加重要,并且可能應(yīng)該是提高伸縮性的第一步
但是這一步可能稍微有的狡猾,Django的admin需要能夠?qū)懮蟼鱩edia到media服務(wù)器(MEDIA_ROOT設(shè)置控制了這些media應(yīng)該寫
到哪兒)如果media位于另外一個服務(wù)器,你將需要安排一種對這個寫跨網(wǎng)絡(luò)發(fā)生的方式
做這個的最簡單的方式是使用NFS來設(shè)置media服務(wù)器的media目錄到web服務(wù)器,如果你設(shè)置它們到MEDIA_ROOT指定的同一位
置,media 上傳將Just Work™
負(fù)載均衡和冗余
在這點上我們現(xiàn)在盡可能多的分解事情,這個三服務(wù)器的設(shè)置應(yīng)該處理非常大的流量--我們從這種架構(gòu)服務(wù)了每天上千萬的
點擊率--所以如果你增長的更多,你將需要開始添加冗余
事實上這是好事:初看一眼上面的圖像顯示了即使三個服務(wù)器中的單獨的一個垮掉了,你將毀掉你的整個站點,所以當(dāng)你添加
額外的服務(wù)器時,你不僅增加了容量,你也增加了可靠性
為了這個例子,讓我們假設(shè)web服務(wù)器首先打擊容量,很容易得到運(yùn)行在不同的硬件上的Django站點的多個拷貝--只需復(fù)制所
有的代碼到多個機(jī)器上,然后在它們上面啟動Apache
盡管如此,你將需要另外一個軟件來在你的多個服務(wù)器上分發(fā)流量:一個負(fù)載均衡器,你可以購買昂貴和私有的硬件負(fù)載均衡
器,但是有一些非常高質(zhì)量的開源負(fù)載均衡器軟件在那里
Apache的mod_proxy就是一個選項,但是我們發(fā)現(xiàn)Perlbal更牛X
它是寫memcached(參考第14章)的一些家伙寫的一個負(fù)載均衡器和倒轉(zhuǎn)代理
注意
如果你使用FastCGI,你可以通過分離你的前臺web服務(wù)器和后端FastCGI進(jìn)程到不同的機(jī)器來達(dá)到同樣的分發(fā)/負(fù)載均衡,前
臺的服務(wù)器本質(zhì)上變成負(fù)載均衡器,后端的FastCGI進(jìn)程則替換了Apache/mod_python/Django服務(wù)器
web服務(wù)器現(xiàn)在集群之后,我們進(jìn)化的架構(gòu)開始看起來更復(fù)雜了:

注意圖像中web服務(wù)器被當(dāng)作"集群"來指出服務(wù)器的數(shù)量是基本可變的,一旦你在前面有一個負(fù)載均衡器,你可以輕松的添加
和刪除后端web服務(wù)器而沒有一丁點的停工期
變大
在這點上,接下來的幾步是最后一步的派生:
1,當(dāng)你需要更多的數(shù)據(jù)庫性能時,你將需要添加復(fù)制數(shù)據(jù)庫服務(wù)器,MySQL包含了內(nèi)建的復(fù)制,PostgreSQL用戶應(yīng)該查詢
Slony和pgpool來分別得到復(fù)制和連接池
2,如果單獨的負(fù)載均衡器不夠,你可以在前面添加更多的負(fù)載均衡器并使用round-robin DNS分發(fā)它們
3,如果單獨的media服務(wù)器不能滿足,你可以添加更多的media服務(wù)器并用你的負(fù)載均衡集群分發(fā)負(fù)載
4,如果你需要更多的緩存,你可以添加專門的緩存服務(wù)器
5,在任何一步,如果集群不能處理的很好你可以添加更多的服務(wù)器到集群
在這些迭代之后,一個高伸縮性的架構(gòu)可能看起來像這樣:

盡管我們只在每個級別顯示了兩到三個服務(wù)器,基本上對你可以添加的服務(wù)器的數(shù)量沒有限制
性能調(diào)優(yōu)
如果你有大量的銀子,對性能問題你可以只是砸硬件,但是對其他人,性能調(diào)優(yōu)是必須的
注意
順便說一下,如果誰有大量的銀子而又正在閱讀本書,請考慮對Django項目的真實的捐獻(xiàn),我們也接受未雕琢的鉆石和金錠
不幸的是,性能調(diào)優(yōu)更多的是一門藝術(shù)而不是一門科學(xué),它甚至比提高伸縮性更難寫,如果你對部署高伸縮性的Django程序
很熱衷,你應(yīng)該花費大量的時間學(xué)習(xí)怎樣調(diào)整你的堆棧的每個部分
但是,這里是一些我們過去幾年討論的Django專有的調(diào)優(yōu)小技巧:
沒有太多的RAM
即使真正昂貴的RAM每千兆字節(jié)只價值$200--盆尼與花費在調(diào)優(yōu)的時間上相比,購買盡可能多的你能負(fù)擔(dān)的起的RAM,然后
再買多一點
更快的處理器不會真的改進(jìn)性能太多,大部分web服務(wù)器花費90%的時間在硬盤IO上,一旦你開始交換,性能將死亡,更快的
硬盤可能稍微有點幫助,但是它們比無關(guān)緊要的RAM昂貴許多
如果你有多個服務(wù)器,放置你的RAM的第一個地方就是數(shù)據(jù)庫服務(wù)器,如果你可以負(fù)擔(dān)的起,得到足夠多的RAM來讓你的整個
數(shù)據(jù)庫放到內(nèi)存中,這應(yīng)該不難,LJWorld.com的數(shù)據(jù)庫--包括回溯至1989年的50萬文章--少于2GB
下一步是對你的web服務(wù)器最大化RAM,理想的情況是永不交換,如果到達(dá)這點你應(yīng)該可以承受大部分普通的流量
關(guān)閉Keep-Alive
Keep-alive是HTTP的一個特性,它允許多個HTTP請求對一個單獨的TCP連接服務(wù),避免了TCP建立/銷毀的過度
第一眼看來這不錯,但是事實上它可以殺掉一個Django站點的性能,如果你恰好從一個單獨的服務(wù)器服務(wù)media,每個瀏覽你
的站點的用戶將事實上最好情況下每10秒從Django服務(wù)器得到一個頁面,這讓HTTP服務(wù)器等待下一個keep-alive請求,而一
個空閑的HTTP服務(wù)器只是消耗一個激活的服務(wù)器應(yīng)該使用的RAM
使用memcached
盡管Django支持許多不同的緩存后端,它們中沒有一個接近memcached一樣快,如果你有一個高流量的站點,不要同時使用
其他緩存后端,直接使用memcached
經(jīng)常使用memecached
當(dāng)然,如果你事實上不使用memcached的話選擇它將不會給你帶來好處,這里第14章是你最好的朋友:學(xué)習(xí)怎樣使用Django的
緩存框架,并且在任何可能的地方使用它,積極的,搶先的緩存通常是保持站點在高流量下的唯一的考慮
加入交談
Django堆棧的每個部分--從Linux到Apache到PostgreSQL或者M(jìn)ySQL--后面都有一個杰出的社區(qū),如果你真正想從你的服務(wù)器
得到最后的1%,參加你的軟件后面的開源社區(qū)并尋求幫助,大部分免費軟件社區(qū)成員將樂于幫助
最后也確認(rèn)加入Django社區(qū),你的卑微的作者們只是一個非常活躍的,成長中的Django開發(fā)人員群組中的兩個成員,我們的
社區(qū)提供一個數(shù)量巨大的集體經(jīng)驗
安徽新華電腦學(xué)校專業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢】