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

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

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

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

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