跳到主要內容

如何使用 Varnish 加速我的網站

編輯此頁面

由於 Symfony 的快取使用標準 HTTP 快取標頭,HTTP 快取 可以替換為任何其他反向代理。Varnish 是一個強大、開放原始碼的 HTTP 加速器,能夠快速提供快取內容,並包含對 邊緣端包含 的支援。

讓 Symfony 信任反向代理

Varnish 會自動將 IP 以 X-Forwarded-For 轉發,並在請求中保留 X-Forwarded-Proto 標頭。如果您未將 Varnish 設定為受信任的代理,Symfony 會將所有請求視為來自 Varnish 主機的不安全 HTTP 連線,而不是真正的用戶端。

請記得在您的前端控制器中呼叫 Request::setTrustedProxies() 方法,以便將 Varnish 視為受信任的代理,並使用 X-Forwarded-* 標頭。

路由和 X-FORWARDED 標頭

為了確保 Symfony Router 使用 Varnish 正確產生 URL,必須存在 X-Forwarded-Port 標頭,Symfony 才能使用正確的埠號。

此埠號對應於您的設定用於接收外部連線的埠(80 是 HTTP 連線的預設值)。如果應用程式也接受 HTTPS 連線,則可能會有另一個代理(因為 Varnish 本身不做 HTTPS)在預設 HTTPS 埠 443 上處理 SSL 終止,並使用 X-Forwarded-Proto 標頭將請求作為 HTTP 請求轉發到 Varnish。在這種情況下,您需要新增以下組態片段

1
2
3
4
5
6
7
sub vcl_recv {
    if (req.http.X-Forwarded-Proto == "https" ) {
        set req.http.X-Forwarded-Port = "443";
    } else {
        set req.http.X-Forwarded-Port = "80";
    }
}

注意

在使用反向代理或負載平衡器時強制使用 HTTPS 需要正確的組態,以避免無限重新導向迴圈;請參閱 如何在負載平衡器或反向代理後方設定 Symfony 以正常運作 以取得更多詳細資訊。

Cookie 和快取

預設情況下,當請求隨附 Cookie 或基本身份驗證標頭 時,大多數快取代理不會快取任何內容。這是因為頁面的內容應該取決於 Cookie 值或身份驗證標頭。

如果您確定後端永遠不會使用 Session 或基本身份驗證,請讓 Varnish 從請求中移除相應的標頭,以防止用戶端繞過快取。實際上,您至少需要在網站的某些部分使用 Session,例如,當使用具有 CSRF 保護 的表單時。在這種情況下,請確保 僅在實際需要時才啟動 Session,並在不再需要時清除 Session。或者,您可以研究 快取包含 CSRF 保護表單的頁面

在 JavaScript 中建立且僅在前端使用的 Cookie,例如來自 Google Analytics 的 Cookie,仍然會傳送到伺服器。這些 Cookie 與後端處理無關,不應影響快取邏輯。為了確保這一點,請設定您的 Varnish 快取以 清理 Cookie 標頭,方法是僅保留必要的 Cookie(例如,Session Cookie)並移除所有其他 Cookie。這樣一來,當沒有活動 Session 時,頁面也可以被快取。

如果您使用預設設定的 PHP,則 Session Cookie 通常命名為 PHPSESSID。此外,如果您的應用程式依賴其他重要的 Cookie,例如用於 記住我 功能的 REMEMBERME Cookie,或用於雙重驗證的受信任裝置 Cookie,也應保留這些 Cookie。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sub vcl_recv {
    // Remove all cookies except for essential ones.
    if (req.http.Cookie) {
        set req.http.Cookie = ";" + req.http.Cookie;
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID|REMEMBERME)=", "; \1=");
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

        if (req.http.Cookie == "") {
            // If there are no more cookies, remove the header to get the page cached.
            unset req.http.Cookie;
        }
    }
}

提示

如果內容並非每個使用者都不同,而是取決於使用者的角色,解決方案是按群組分隔快取。此模式由 FOSHttpCacheBundle使用者情境 的名稱實作和說明。

確保一致的快取行為

Varnish 使用您的應用程式傳送的快取標頭來決定如何快取內容。但是,Varnish 4 之前的版本不遵守 Cache-Control: no-cacheno-storeprivate。為了確保行為一致,如果您仍在使用 Varnish 3,請使用以下組態

1
2
3
4
5
6
7
8
9
10
sub vcl_fetch {
    // By default, Varnish3 ignores Cache-Control: no-cache and private
    // https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control
    if (beresp.http.Cache-Control ~ "private" ||
        beresp.http.Cache-Control ~ "no-cache" ||
        beresp.http.Cache-Control ~ "no-store"
    ) {
        return (hit_for_pass);
    }
}

提示

您可以在 VCL 檔案的形式中看到 Varnish 的預設行為:Varnish 3 的 default.vcl,Varnish 4 的 builtin.vcl

啟用邊緣端包含 (ESI)

邊緣端包含文章 中所述,Symfony 會偵測它是否與理解 ESI 的反向代理通訊。當您使用 Symfony 反向代理時,您無需執行任何操作。但是,為了讓 Varnish 而不是 Symfony 解析 ESI 標籤,您需要在 Varnish 中進行一些組態。Symfony 使用來自 Akamai 描述的 邊緣架構Surrogate-Capability 標頭。

注意

Varnish 僅支援 ESI 標籤的 src 屬性(onerroralt 屬性會被忽略)。

首先,設定 Varnish,使其透過將 Surrogate-Capability 標頭新增至轉發到後端應用程式的請求來宣告其 ESI 支援

1
2
3
4
sub vcl_recv {
    // Add a Surrogate-Capability header to announce ESI support.
    set req.http.Surrogate-Capability = "abc=ESI/1.0";
}

注意

標頭的 abc 部分並不重要,除非您有多個需要宣告其功能的「代理」。請參閱 代理功能標頭 以取得詳細資訊。

然後,最佳化 Varnish,使其僅在至少有一個 ESI 標籤時才解析回應內容,方法是檢查 Symfony 自動新增的 Surrogate-Control 標頭

1
2
3
4
5
6
7
sub vcl_backend_response {
    // Check for ESI acknowledgement and remove Surrogate-Control header
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_esi = true;
    }
}

提示

如果您遵循了關於確保一致快取行為的建議,則這些 VCL 函數已經存在。將程式碼附加到函數的末尾,它們不會互相干擾。

快取失效

如果您想要快取經常變更的內容,並且仍然向使用者提供最新版本,則需要使該內容失效。雖然 快取失效 允許您在內容過期之前從代理中清除內容,但這會增加快取設定的複雜性。

提示

開放原始碼 FOSHttpCacheBundle 透過協助您組織快取和失效設定,消除了快取失效的痛苦。

FOSHttpCacheBundle 的文件說明了如何為快取失效設定 Varnish 和其他反向代理。

這項作品,包括程式碼範例,已根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本