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

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

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

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

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