第十二章: 部署Django

第十二章: 部署Django

本章包含建立一個django程序最必不可少的步驟 在服務器上部署它php

若是你一直跟着咱們的例子作,你可能正在用runserver 可是runserver 要部署你的django程序,你須要掛接到工業用的服務器 如:Apache 在本章,咱們將展現如何作,可是,在作以前咱們要給你一個(要作的事的)清單.html

準備你的代碼庫

很幸運,runserver 可是,在開始前,有一些**python

關閉Debug模式.

咱們在第2章,用命令 django-admin.py startproject建立了一個項目 , 其中建立的 settings.py 文件的 DEBUG 設置默認爲 True . django會根據這個設置來改變他們的行爲, 若是 DEBUG 模式被開啓. 例如, 若是 DEBUG 被設置成 True , 那麼:linux

  • 全部的數據庫查詢將被保存在內存中, 以 django.db.connection.queries 的形式. 你能夠想象,這個吃內存!程序員

  • 任何404錯誤都將呈現django的特殊的404頁面(第3章有)而不是普通的404頁面。 這個頁面包含潛在的敏感信息,可是不會暴露在公共互聯網。web

  • 你的應用中任何未捕獲的異常,從基本的python語法錯誤到數據庫錯誤以及模板語法錯誤都會返回漂亮的Django錯誤頁面。 這個頁面包含了比404錯誤頁面更多的敏感信息,因此這個頁面絕對不要公開暴露。正則表達式

簡單的說,把`` DEBUG`` 設置成`` True`` 至關於告訴Django你的網站只會被可信任的開發人員使用。 Internet裏充滿了不可信賴的事物,當你準備部署你的應用時,首要的事情就是把`` DEBUG`` 設置爲`` False`` 。sql

來關閉模板Debug模式。

相似地,你應該在生產環境中把TEMPLATE_DEBUGFalse 若是這個設爲`` True`` ,爲了在那個好看的錯誤頁面上顯示足夠的東西,Django的模版系統就會爲每個模版保存一些額外的信息。數據庫

實現一個404模板

若是`` DEBUG`` 設置爲`` True`` ,Django會顯示那個自帶的404錯誤頁面。 但若是`` DEBUG`` 被設置成`` False`` ,那它的行爲就不同了: 他會顯示一個在你的模版根目錄中名字叫`` 404.html`` 的模版 因此,當你準備部署你的應用時,你會須要建立這個模版並在裏面放一些有意義的「頁面未找到」的信息apache

這裏有一個`` 404.html``的示例,你能夠從它開始。 假定你使用的模板繼承並定義一個 `` base.html``,該頁面由titlecontent兩塊組成。

{% extends "base.html" %}

{% block title %}Page not found{% endblock %}

{% block content %}
<h1>Page not found</h1>

<p>Sorry, but the requested page could not be found.</p>
{% endblock %}

要測試你的404.html頁面是否正常工做,僅僅須要將DEBUG 設置爲`` False`` ,而且訪問一個並不存在的URL。 (它將在`` sunserver`` 上工做的和開發服務器上同樣好)

實現一個500模板

相似的,若是`` DEBUG`` 設置爲`` False`` ,Djang再也不會顯示它自帶的應對未處理的Python異常的錯誤反饋頁面。 做爲代替,它會查找一個名爲`` 500.html`` 的模板而且顯示它。 像`` 404.html`` 同樣,這個模板應該被放置在你的模板根目錄下。

這裏有一個關於500.html的比較棘手的問題。你永遠不能肯定`` 爲何``會顯示這個模板,因此它不該該作任何須要鏈接數據庫,或者依賴任何可能被破壞的基礎構件的事情。 (例如:它不該該使用自定義模板標籤。)若是它用到了模板繼承,那麼父模板也就不該該依賴可能被破壞的基礎構件。 所以,最好的方法就是避免模板繼承,而且用一些很是簡單的東西。 這是一個`` 500.html`` 的例子,能夠把它做爲一個起點:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
    <title>Page unavailable</title>
</head>
<body>
    <h1>Page unavailable</h1>

    <p>Sorry, but the requested page is unavailable due to a
    server hiccup.</p>

    <p>Our engineers have been notified, so check back later.</p>
</body>
</html>

設置錯誤警告

當你使用Django製做的網站運行中出現了異常,你會但願去了解以便於修正它。 默認狀況下,Django在你的代碼引起未處理的異常時,將會發送一封Email至開發者團隊。但你須要去作兩件事來設置這種行爲。

首先,改變你的ADMINS設置用來引入你的E-mail地址,以及那些任何須要被注意的聯繫人的E-mail地址。 這個設置採用了相似於(姓名, Email)元組,像這樣:

ADMINS = (
    ('John Lennon', 'jlennon@example.com'),
    ('Paul McCartney', 'pmacca@example.com'),
)

第二,確保你的服務器配置爲發送電子郵件。 設置好postfix,sendmail或其餘本書範圍以外可是與Django設置相關的郵件服務器,你須要將將 EMAIL_HOST設置爲你的郵件服務器的正確的主機名. 默認模式下是設置爲’localhost’, 這個設置對大多數的共享主機系統環境適用. 取決於你的安排的複雜性,你可能還須要設置 EMAIL_HOST_USER,EMAIL_HOST_PASSWORD,EMAIL_PORT或EMAIL_USE_TLS。

你還能夠設置EMAIL_SUBJECT_PREFIX以控制Django使用的 error e-mail的前綴。 默認狀況下它被設置爲'[Django] '

設置鏈接中斷警報

若是你安裝有CommonMiddleware(好比,你的MIDDLEWARE_CLASSES設置 包含了’django.middleware.common.CommonMiddleware’的狀況下,默認就安裝了 CommonMiddleware),你就具備了設置這個選項的能力:有人在訪問你的Django網站的一個非空的連接而致使一個404錯誤的發生和鏈接 中斷的狀況,你將收到一封郵件. 若是你想激活這個特性,設置SEND_BROKEN_LINK_EMAILS 爲True(默認爲False),並設置你的MANAGERS爲某我的或某些人的郵件地址,這些郵件地址將會收到報告鏈接中斷錯誤的郵件. MANAGERS使用和ADMINS 一樣的語法.例如:

MANAGERS = (
    ('George Harrison', 'gharrison@example.com'),
    ('Ringo Starr', 'ringo@example.com'),
)

請注意,錯誤的Email會使人感到反感,對於任何人來講都是這樣。

使用針對產品的不一樣的設置

在此書中,咱們僅僅處理一個單一的設置文件 settings.py文件由django-admin.py startproject命令生成。可是當你準備要進行配置的時候,你將發現你須要多個配置文件以使你的開發環境和產品環境相獨立。 好比,你可能不想每次在本地機器上測試代碼改變的時候將DEBUG從False 改成True。Django經過使用多個配置文件而使得這種狀況很容易獲得避免。

若是你想把你的配置文件按照產品設置和開發設置組織起來,你能夠經過下面三種方法的其中一種達到這個目的。

  • 設置成兩個全面的,彼此獨立的配置文件

  • 設置一個基本的配置文件(好比,爲了開發)和第二個(爲了產品)配置文件,第二個配置文件僅僅從基本的那個配置文件導入配置,並對須要定義的進行復寫.

  • 使用一個單獨的配置文件,此配置文件包含一個Python的邏輯判斷根據上下文環境改變設置。

咱們將會在依次解釋這幾種方式

首先,最基本的方法是定義兩個單獨的配置文件。 若是你是跟隨以前的例子作下來的,那麼你已經有了一個settings.py了,如今你只須要將它複製一份並命名爲 settings_production.py(文件名能夠按照你本身的喜愛定義),在這個新文件中改變DEBUG等設置。

第二種方法比較相似,可是減小了許多冗餘。 做爲使用兩個內容大部分相同的配置文件的替代方式,你可使用一個文件爲基本文件,另一個文件從基本文件中導入相關設定。 例如

# settings.py

DEBUG = True
TEMPLATE_DEBUG = DEBUG

DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'devdb'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_PORT = ''

# ...

# settings_production.py

from settings import *

DEBUG = TEMPLATE_DEBUG = False
DATABASE_NAME = 'production'
DATABASE_USER = 'app'
DATABASE_PASSWORD = 'letmein'

此處,settings_production.py 從settings.py 導入全部的設定,僅僅只是從新定義了產品模式下須要特殊處理的設置。 在這個案例中,DEBUG 被設置爲False,可是咱們已經對產品模式設置了不一樣的數據庫訪問參數。 (後者將向你演示你能夠從新定義 任何 設置,並不僅是象 DEBUG 這樣的基本設置。)

最終,最精簡的達到兩個配置環境設定的方案是使用一個配置文件,在此配置文件中根據不一樣的環境進行設置。 一個達到這個目的的方法是檢查當前的主機名。 例如:

# settings.py

import socket

if socket.gethostname() == 'my-laptop':
    DEBUG = TEMPLATE_DEBUG = True
else:
    DEBUG = TEMPLATE_DEBUG = False

# ...

在這裏,咱們從python標準庫導入了socket 模塊,使用它來檢查當前系統的主機名。 咱們能夠經過檢查主機名來確認代碼是否運行在產品服務器上。

一個關鍵是配置文件僅僅是包含python代碼的文件。你能夠從其餘文件導入這些python代碼,可 以經過這些代碼執行任意的邏輯判斷等操做。 若是你打算按照這種方案走下去,請肯定這些配置文件中的代碼是足夠安全(防彈)的。 若是這個配置文件拋出任何的異常,Django都有可能會發生很嚴重的崩潰。

重命名settings.py

隨便將你的settings.py重命名爲settings_dev.py或settings/dev.py或foobar.py,Django 並不在意你的配置文件取什麼名字,只要你告訴它你使用的哪一個配置文件就能夠了。

可是若是你真的重命名了由django-admin.py startproject 命令建立的settings.py文件,你會發現manage.py會給出一個錯誤信息說找不到配置文件。 那是因爲它嘗試從這個文件中導入一個叫作settings的模塊,你能夠經過修改manage.py 文件,將 import settings 語句改成導入你本身的模塊,或者使用django-admin.py而不是使用manage.py,在後一種方式中你須要設置 DJANGO_SETTINGS_MODULE 環境變量爲你的配置文件所在的python 路徑.(好比’mysite.settings’)。

DJANGO_SETTINGS_MODULE

經過這種方式的代碼改變後,本章的下一部分將集中在對具體環境(好比Apache)的發佈所須要的指令 上。 這些指令針對每一種環境都不一樣,可是有一件事情是相同的。 在每一種環境中,你都須要告訴Web服務器你的DJANGO_SETTINGS_MODULE是什麼,這是你的Django應用程序的進入點。 DJANGO_SETTINGS_MODULE指向你的配置文件,在你的配置文件中指向你的ROOT_URLCONF,在ROOT_URLCONF中指向 了你的視圖以及其餘的部分。

DJANGO_SETTINGS_MODULE是你的配置文件的python的路徑 好比,假設mysite是在你的Python路徑中,DJANGO_SETTINGS_MODULE對於咱們正在進行的例子就是’mysite.settings’。

用Apache和mod_python來部署Django

目前,Apache和mod_python是在生產服務器上部署Django的最健壯搭配。

mod_python (http://www.djangoproject.com/r/mod_python/)是一個在Apache中嵌入Python的Apache插件,它在服務器啓動時將Python代碼加載到內存中。 (譯註:

Django 須要Apaceh 2.x 和mod_python 3.x支持。

備註

如何配置Apache超出了本書的範圍,所以下面將只簡單介紹必要的細節。 幸運的是,若是須要進一步學習Apache的相關知識,能夠找到至關多的絕佳資源。 咱們喜歡去的幾個地方:

基本配置

爲了配置基於 mod_python 的 Django,首先要安裝有可用的 mod_python 模塊的 Apache。 這一般意味着應該有一個 LoadModule 指令在 Apache 配置文件中。 它看起來就像是這樣:

LoadModule python_module /usr/lib/apache2/modules/mod_python.so

Then, edit your Apache configuration file and add a <Location> directive that ties a specific URL path to a specific Django installation. 例如:

<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonDebug Off
</Location>

要確保把 DJANGO_SETTINGS_MODULE 中的 mysite.settings 項目換成與你的站點相應的內容。

它告訴 Apache,任何在 / 這個路徑以後的 URL 都使用 Django 的 mod_python 來處理。 它 將 DJANGO_SETTINGS_MODULE 的值傳遞過去,使得 mod_python 知道這時應該使用哪一個配置。

注意這裏使用 ```` 指令而不是 ```` 。 後者用於指向你的文件系統中的一個位置,然而 ````

System Message: WARNING/2 (<string>, line 403); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<string>, line 403); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<string>, line 403); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<string>, line 403); backlink

Inline literal start-string without end-string.

System Message: ERROR/3 (<string>, line 405)

Unexpected indentation.

指向一個 Web 站點的 URL 位置。 ````

System Message: WARNING/2 (<string>, line 405); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<string>, line 405); backlink

Inline literal start-string without end-string.

Apache 可能不但會運行在你正常登陸的環境中,也會運行在其它不一樣的用戶環境中;也可能會有不一樣的文件路徑或 sys.path。 你須要告訴 mod_python 如何去尋找你的項目及 Django 的位置。

PythonPath "['/path/to/project', '/path/to/django'] + sys.path"

你也能夠加入一些其它指令,好比 PythonAutoReload Off 以提高性能。 查看 mod_python 文檔得到詳細的指令列表。

注意,你應該在成品服務器上設置 PythonDebug Off 。若是你使用 PythonDebug On 的話,在程序產生錯誤時,你的用戶會看到難看的(而且是暴露的) Python 回溯信息。 若是你把 PythonDebug 置 On,當mod_python出現某些錯誤,你的用戶會看到醜陋的(也會暴露某些信息)Python的對錯誤的追蹤的信息。

重啓 Apache 以後全部對你的站點的請求(或者是當你用了 <VirtualHost> 指令後則是虛擬主機)都會由 Djanog 來處理。

在同一個 Apache 的實例中運行多個 Django 程序

在同一個 Apache 實例中運行多個 Django 程序是徹底可能的。 當你是一個獨立的 Web 開發人員並有多個不一樣的客戶時,你可能會想這麼作。

只要像下面這樣使用 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> 指令分別解釋:

<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>

這個 PythonInterpreter 中的值不重要,只要它們在兩個 Location 塊中不一樣。

用 mod_python 運行一個開發服務器

由於 mod_python 緩存預載入了 Python 的代碼,當在 mod_python 上發佈 Django 站點時,你每 改動了一次代碼都要須要重啓 Apache 一次。 這還真是件麻煩事,因此這有個辦法來避免它: 只要 加入 MaxRequestsPerChild 1 到配置文件中強制 Apache 在每一個請求時都從新載入全部的 代碼。 可是不要在產品服務器上使用這個指令,這會撤銷 Django 的特權。

若是你是一個用分散的 print 語句(咱們就是這樣)來調試的程序員,注意這 print 語 句在 mod_python 中是無效的;它不會像你但願的那樣產生一個 Apache 日誌。 若是你須要在 mod_python 中打印調試信息,可能須要用到 Python 標準日誌包(Pythons standard logging package)。 更多的信息請參見 http://docs.python.org/lib/module-logging.html 。另外一個選擇是在模板頁面中加入調試信息。

使用相同的Apache實例來服務Django和Media文件

Django自己不用來服務media文件;應該把這項工做留給你選擇的網絡服務器。 咱們推薦使用一個單獨的網絡服務器(即沒有運行Django的一個)來服務media。 想了解更多信息,看下面的章節。

不過,若是你沒有其餘選擇,因此只能在同Django同樣的Apache VirtualHost 上服務media文件,這裏你能夠針對這個站點的特定部分關閉mod_python:

<Location "/media/">
    SetHandler None
</Location>

將 Location 改爲你的media文件所處的根目錄。

你也可使用 <LocationMatch> 來匹配正則表達式。 好比,下面的寫法將Django定義到網站的根目錄,而且顯式地將 media 子目錄以及任何以 .jpg , .gif , 或者 .png 結尾的URL屏蔽掉:

<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>

在全部這些例子中,你必須設置 DocumentRoot ,這樣apache才能知道你存放靜態文件的位置。

錯誤處理

當你使用 Apache/mod_python 時,錯誤會被 Django 捕捉,它們不會傳播到 Apache 那裏,也不會出如今 Apache 的 錯誤日誌 中。

除非你的 Django 設置的確出了問題。 在這種狀況下,你會在瀏覽器上看到一個 內部服務器錯誤的頁面,並在 Apache 的 錯誤日誌 中看到 Python 的完整回溯信息。 錯誤日誌 的回溯信息有多行。 固然,這些信息是難看且難以閱讀的。

處理段錯誤

有時候,Apache會在你安裝Django的時候發生段錯誤。 這時,基本上 老是 有如下兩個與Django自己無關的緣由其中之一所形成:

  • 有多是由於,你使用了 pyexpat 模塊(進行XML解析)而且與Apache內置的版本相沖突。 詳情請見 http://www.djangoproject.com/r/articles/expat-apache-crash/.

  • 也有多是在同一個Apache進程中,同時使用了mod_python 和 mod_php,並且都使用MySQL做爲數據庫後端。 在有些狀況下,這會形成PHP和Python的MySQL模塊的版本衝突。 在mod_python的FAQ中有更詳細的解釋。

若是還有安裝mod_python的問題,有一個好的建議,就是先只運行mod_python站點,而不使用Django框架。 這是區分mod_python特定問題的好方法。 下面的這篇文章給出了更詳細的解釋。 http://www.djangoproject.com/r/articles/getting-modpython-working/.

下一個步驟應該是編輯一段測試代碼,把你全部django相關代碼import進去,你的 views,models,URLconf,RSS配置,等等。 把這些imports放進你的handler函數中,而後從瀏覽器進入你的URL。 若是這些致使了crash,你就能夠肯定是import的django代碼引發了問題。 逐個去掉這些imports,直到再也不衝突,這樣就能找到引發問題的那個模塊。 深刻了解各模塊,看看它們的imports。 要想得到更多幫助,像linux的ldconfig,Mac OS的otool和windows的ListDLLs(form sysInternals)均可以幫你識別共享依賴和可能的版本衝突。

一種替代方案: mod_wsgi模塊

做爲一個mod_python模塊的替代,你能夠考慮使用mod_wsgi模塊(http://code.google.com/p/modwsgi/),此模塊開發的時間比mod_python的開發時間離如今更近一些,在Django社區已有一些使用。 一個完整的概述超出了本書的範圍,你能夠從官方的Django文檔查看到更多的信息。

使用FastCGI部署Django應用

儘管將使用Apache和mod_python搭建Django環境是最具魯棒性的,但在不少虛擬主機平臺上,每每只能使用FastCGI

此外,在不少狀況下,FastCGI可以提供比mod_python更爲優越的安全性和效能。 針對小型站點,相對於Apache來講FastCGI更爲輕量級。

FastCGI 簡介

如何可以由一個外部的應用程序頗有效解釋WEB 服務器上的動態頁面請求呢? 答案就是使用FastCGI! 它的工做步驟簡單的描述起來是這樣的:

和mod_python同樣,FastCGI也是駐留在內存裏爲客戶請求返回動態信息,並且也免掉了像傳統的CGI同樣啓動進程時候的時間花銷。 但於mod_python不一樣之處是它並非做爲模塊運行在web服務器同一進程內的,而是有本身的獨立進程。

爲何要在一個獨立的進程中運行代碼?

在以傳統的方式的幾種以mod_*方式嵌入到Apache的腳本語言中(常見的例如: PHP,Python/mod_python和Perl/mod_perl),他們都是以apache擴展模塊的方式將自身嵌入到Apache進程中的。

每個Apache進程都是一個Apache引擎的副本,它徹底包括了全部Apache所具備的一切功能特性(哪怕是對Django毫無好處的東西也一併加載進來)。 而FastCGI就不同了,它僅僅把Python和Django等必備的東東弄到內存中。

依據FastCGI自身的特色能夠看到,FastCGI進程能夠與Web服務器的進程分別運行在不一樣的用戶權限下。 對於一個多人共用的系統來講,這個特性對於安全性是很是有好處的,由於你能夠安全的於別人分享和重用代碼了。

若是你但願你的Django以FastCGI的方式運行,那麼你還必須安裝 flup 這個Python庫,這個庫就是用於處理FastCGI的。 不少用戶都抱怨 flup 的發佈版過久了,總是不更新。 其實不是的,他們一直在努力的工做着,這是沒有放出來而已。

運行你的 FastCGI 服務器

FastCGI是以客戶機/服務器方式運行的,而且在不少狀況下,你得本身去啓動FastCGI的服 務進程。 Web服務器(例如Apache,lighttpd等等)僅僅在有動態頁面訪問請求的時候纔會去與你的Django-FastCGI進程交互。 由於Fast-CGI已經一直駐留在內存裏面了的,因此它響應起來也是很快的。

記錄

在虛擬主機上使用的話,你可能會被強制的使用Web server-managed FastCGI進程。 在這樣的狀況下,請參閱下面的「在Apache共享主機裏運行Django」這一小節。

web服務器有兩種方式於FastCGI進程交互: 使用Unix domain socket(在win32裏面是 命名管道 )或者使用TCP socket.具體使用哪個,那就根據你的偏好而定了,可是TCP socket弄很差的話每每會發生一些權限上的問題。 What you choose is a manner of preference; a TCP socket is usually easier due to permissions issues.

開始你的服務器項目,首先進入你的項目目錄下(你的 manage.py 文件所在之處),而後使用 manage.py runfcgi 命令:

./manage.py runfcgi [options]

想了解如何使用 runfcgi ,輸入 manage.py runfcgi help 命令。

你能夠指定 socket 或者同時指定 host 和 port 。當你要建立Web服務器時,你只須要將服務器指向當你在啓動FastCGI服務器時肯定的socket或者host/port。

範例:

在TCP端口上運行一個線程服務器:

./manage.py runfcgi method=threaded host=127.0.0.1 port=3033

在Unix socket上運行prefork服務器:

./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid

啓動,但不做爲後臺進程(在調試時比較方便):

./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock

中止FastCGI的行程

若是你的FastCGI是在前臺運行的,那麼只需按Ctrl+C就能夠很方便的中止這個進程了。 但若是是在後臺運行的話,你就要使用Unix的 kill 命令來殺掉它。 然而,當你正在處理後臺進程時,你會須要將其付諸於Unix kill的命令

若是你在 manage.py runfcgi 中指定了 pidfile 這個選項,那麼你能夠這樣來殺死這個FastCGI後臺進程:

kill `cat $PIDFILE`

$PIDFILE 就是你在 pidfile 指定的那個。

你可使用下面這個腳本方便地重啓Unix裏的FastCGI守護進程:

#!/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的方式使用Django

在Apache和FastCGI上使用Django,你須要安裝和配置Apache,而且安裝mod_fastcgi。 請參見Apache和mod_fastcgi文檔: http://www.djangoproject.com/r/mod_fastcgi/ 。

當完成了安裝,經過 httpd.conf (Apache的配置文件)來讓Apache和Django FastCGI互相通訊。 你須要作兩件事:

  • 使用 FastCGIExternalServer 指明FastCGI的位置。

  • 使用 mod_rewrite 爲FastCGI指定合適的URL。

指定 FastCGI Server 的位置

FastCGIExternalServer 告訴Apache如何找到FastCGI服務器。 按照FastCGIExternalServer 文檔( http://www.djangoproject.com/r/mod_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/ 目錄必須存在,而 /home/user/public_html/mysite.fcgi 文件不必定存在。 它僅僅是一個Web服務器內部使用的接口,這個URL決定了對於哪些URL的請求會被FastCGI處理(下一部分詳細討論)。 (下一章將會有更多有關於此的介紹)

使用mod_rewrite爲FastCGI指定URL

第二步是告訴Apache爲符合必定模式的URL使用FastCGI。 爲了實現這一點,請使用mod_rewrite 模塊,並將這些URL重定向到 mysite.fcgi (或者正如在前文中描述的那樣,使用任何在 FastCGIExternalServer 指定的內容)。

在這個例子裏面,咱們告訴Apache使用FastCGI來處理那些在文件系統上不提供文件(譯者注:

<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 (http://www.djangoproject.com/r/lighttpd/) 是一個輕量級的Web服務器,一般被用來提供靜態頁面的訪問。 它天生支持FastCGI,所以除非你的站點須要一些Apache特有的特性,不然,lighttpd對於靜態和動態頁面來講都是理想的選擇。

確保 mod_fastcgi 在模塊列表中,它須要出如今 mod_rewrite 和 mod_access ,可是要在 mod_accesslog 以前。

將下面的內容添加到你的lighttpd的配置文件中:

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。

記錄

若是你要使用服務器的子進程,你沒有必要本身去啓動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 或者編輯改文件,使得修改時間發生了變化,它會自動幫你重啓Django應用。 你能夠從新上傳mysite.fcgi或者編輯這個文件以改變該文件的時間戳。 當阿帕奇服務器發現文檔被更新了,它將會爲你重啓你的Django應用。

若是你擁有Unix系統命令行的可執行權限,只須要簡單地使用 touch 命令:

touch mysite.fcgi

可擴展性

既然你已經知道如何在一臺服務器上運行Django,讓咱們來研究一下,如何擴展咱們的Django安裝。 這一部分咱們將討論,如何把一臺服務器擴展爲一個大規模的服務器集羣,這樣就能知足每小時上百萬的點擊率。

有一點很重要,每個大型的站點大的形式和規模不一樣,所以可擴展性其實並非一種千篇一概的行爲。 如下部分會涉及到一些通用的原則,而且會指出一些不一樣選擇。

首先,咱們來作一個大的假設,只集中地討論在Apache和mod_python下的可擴展性問題。 儘管咱們也知道一些成功的中型和大型的FastCGI策略,可是咱們更加熟悉Apache。

運行在一臺單機服務器上

大多數的站點一開始都運行在單機服務器上,看起來像圖20-1這樣的構架。

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-1.png

圖 20-1: 一個單服務器的Django安裝。

這對於小型和中型的站點來講還不錯,而且也很便宜,通常來講,你能夠在3000美圓如下就搞定一切。

然而,當流量增長的時候,你會迅速陷入不一樣軟件的 資源爭奪 之中。 數據庫服務器和Web服務器都 喜歡 本身擁有整個服務器資源,所以當被安裝在單機上時,它們總會爭奪相同的資源(RAM, CPU),它們更願意獨享資源。

經過把數據庫服務器搬移到第二臺主機上,能夠很容易地解決這個問題。

分離出數據庫服務器

對於Django來講,把數據庫服務器分離開來很容易: 只須要簡單地修改 DATABASE_HOST ,設置爲新的數據庫服務器的IP地址或者DNS域名。 設置爲IP地址老是一個好主意,由於使用DNS域名,還要牽涉到DNS服務器的可靠性鏈接問題。

使用了一個獨立的數據庫服務器之後,咱們的構架變成了圖20-2。

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-2.png

圖 20-2: 將數據庫移到單獨的服務器上。

這裏,咱們開始步入 n-tier 構架。 不要被這個詞所嚇壞,它只是說明了Web棧的不一樣部分,被分離到了不一樣的物理機器上。

咱們再來看,若是發現須要不止一臺的數據庫服務器,考慮使用鏈接池和數據庫備份將是一個好主意。 不幸的是,本書沒有足夠的時間來討論這個問題,因此你參考數據庫文檔或者向社區求助。

運行一個獨立的媒體服務器

使用單機服務器仍然留下了一個大問題: 處理動態內容的媒體資源,也是在同一臺機器上完成的。

這兩個活動是在不一樣的條件下進行的,所以把它們強行湊和在同一臺機器上,你不可能得到很好的性能。 下一步,咱們要把媒體資源(任何 不是 由Django視圖產生的東西)分離到別的服務器上(請看圖20-3)。

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-3.png

圖 20-3: 分離出媒體服務器。

理想的狀況是,這個媒體服務器是一個定製的Web服務器,爲傳送靜態媒體資源作了優化。 lighttpd和tux (http://www.djangoproject.com/r/tux/) 都是極佳的選擇,固然瘦身的Apache服務器也能夠工做的很好。

對於擁有大量靜態內容(照片、視頻等)的站點來講,將媒體服務器分離出去顯然有着更加劇要的意義,並且應該是擴大規模的時候所要採起的 第一步措施 。

這一步須要一點點技巧,Django的admin管理接口須要可以得到足夠的權限來處理上傳的媒體(經過設置 MEDIA_ROOT )。若是媒體資源在另外的一臺服務器上,你須要得到經過網絡寫操做的權限。 若是你的應用牽涉到文件上載,Django須要可以面向媒體服務器撰寫上載媒體 若是媒體是在另一臺服務器上的,你須要部署一種方法使得Django能夠經過網絡去寫這些媒體。

實現負擔均衡和數據冗餘備份

如今,咱們已經儘量地進行了分解。 這種三臺服務器的構架能夠承受很大的流量,好比天天1000萬的點擊率。

這是個好主意。 請看圖 20-3,一旦三個服務器中的任何一個發生了故障,你就得關閉整個站點。 所以在引入冗餘備份的時候,你並不僅是增長了容量,同時也增長了可靠性。

咱們首先來考慮Web服務器的點擊量。 把同一個Django的站點複製多份,在多臺機器上同時運行很容易,咱們也只須要同時運行多臺機器上的Apache服務器。

你還須要另外一個軟件來幫助你在多臺服務器之間均衡網絡流量: 流量均衡器(load balancer) 。你能夠購買昂貴的專有的硬件均衡器,固然也有一些高質量的開源的軟件均衡器可供選擇。

Apaches 的 mod_proxy 是一個能夠考慮的選擇,但另外一個配置更棒的選擇是: memcached是同一個團隊的人寫的一個負載均衡和反向代理的程序.(見第15章)

記錄

若是你使用FastCGI,你一樣能夠分離前臺的web服務器,並在多臺其餘機器上運行 FastCGI服務器來實現相同的負載均衡的功能。 前臺的服務器就至關因而一個均衡器,然後臺的FastCGI服務進程代替了Apache/mod_python/Django服務器。

如今咱們擁有了服務器集羣,咱們的構架慢慢演化,愈來愈複雜,如圖20-4。

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-4.png

圖 20-4: 負載均衡的服務器設置。

值得一提的是,在圖中,Web服務器指的是一個集羣,來表示許多數量的服務器。 一旦你擁有了一個前臺的均衡器,你就能夠很方便地增長和刪除後臺的Web服務器,並且不會形成任何網站不可用的時間。

慢慢變大

下面的這些步驟都是上面最後一個的變體:

  • 當你須要更好的數據庫性能,你可能須要增長數據庫的冗餘服務器。 MySQL內置了備份功能;PostgreSQL應該看一下Slony (http://www.djangoproject.com/r/slony/) 和 pgpool (http://www.djangoproject.com/r/pgpool/) ,這兩個分別是數據庫備份和鏈接池的工具。

  • 若是單個均衡器不能達到要求,你能夠增長更多的均衡器,而且使用輪訓(round-robin)DNS來實現分佈訪問。

  • 若是單臺媒體服務器不夠用,你能夠增長更多的媒體服務器,並經過集羣來分佈流量。

  • 若是你須要更多的高速緩存(cache),你能夠增長cache服務器。

  • 在任何狀況下,只要集羣工做性能很差,你均可以往上增長服務器。

重複了幾回之後,一個大規模的構架會像圖20-5。

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-5.png

圖 20-5。 大規模的Django安裝。

儘管咱們只是在每一層上展現了兩到三臺服務器,你能夠在上面隨意地增長更多。

性能優化

若是你有大筆大筆的錢,遇到擴展性問題時,你能夠簡單地投資硬件。 對於剩下的人來講,性能優化就是必需要作的一件事。

注意

順便提一句,誰要是有大筆大筆的鈔票,請捐助一點Django項目。 咱們也接受未切割的鑽石和金幣。

不幸的是,性能優化比起科學來講更像是一種藝術,而且這比擴展性更難描述。 若是你真想要構建一個大規模的Django應用,你須要花大量的時間和精力學習如何優化構架中的每一部分。

如下部分總結了多年以來的經驗,是一些專屬於Django的優化技巧。

RAM怎麼也不嫌多

最近即便那些昂貴的RAM也相對來講能夠負擔的起了。 購買儘量多的RAM,再在別的上面投資一點點。

高速的處理器並不會大幅度地提升性能;大多數的Web服務器90%的時間都浪費在了硬盤IO上。 當硬盤上的數據開始交換,性能就急劇降低。 更快速的硬盤能夠改善這個問題,可是比起RAM來講,那太貴了。

若是你擁有多臺服務器,首要的是要在數據庫服務器上增長內存。 若是你能負擔得起,把你整個數據庫都放入到內存中。 這應該不是很困難,咱們已經開發過一個站點上面有多於一百萬條報刊文章,這個站點使用了不到2GB的空間。

下一步,最大化Web服務器上的內存。 最理想的狀況是,沒有一臺服務器進行磁盤交換。 若是你達到了這個水平,你就能應付大多數正常的流量。

禁用 Keep-Alive

Keep-Alive 是HTTP提供的功能之一,它的目的是容許多個HTTP請求複用一個TCP鏈接,也就是容許在同一個TCP鏈接上發起多個HTTP請求,這樣有效的避免了每一個HTTP請求都從新創建本身的TCP鏈接的開銷。

這一眼看上去是好事,但它足以殺死Django站點的性能。 若是你從單獨的媒體服務器上向用戶提供服務,每一個光顧你站點的用戶都大約10秒鐘左右發出一次請求。 這就使得HTTP服務器一直在等待下一次keep-alive 的請求,空閒的HTTP服務器和工做時消耗同樣多的內存。

使用 memcached

儘管Django支持多種不一樣的cache後臺機制,沒有一種的性能能夠 接近 memcached。 若是你有一個高流量的站點,不要猶豫,直接選擇memcached。

常用memcached

固然,選擇了memcached而不去使用它,你不會從中得到任何性能上的提高。 Chapter 15 is your best friend here: 學習如何使用Django的cache框架,而且儘量地使用它。 大量的可搶佔式的高速緩存一般是一個站點在大流量下正常工做的惟一瓶頸。

參加討論

Django相關的每個部分,從Linux到Apache到PostgreSQL或者MySQL背後,都有一個很是棒的社區支持。 若是你真想從你的服務器上榨乾最後1%的性能,加入開源社區尋求幫助。 多數的自由軟件社區成員都會很樂意地提供幫助。

別忘了Django社區。 這本書謙遜的做者只是Django開發團隊中的兩位成員。 咱們的社區有大量的經驗能夠提供。

相關文章
相關標籤/搜索