歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux管理 >> Linux配置

配置Varnish加速你的Web網站

Varnish可以有效降低web服務器的負載,提升訪問速度。根據官方的說法,Varnish是一個cache型的HTTP反向代理。

按照HTTP協議的處理過程,web服務器接受請求並且返回處理結果,理想情況下服務器要在不做額外處理的情況下,立即返回結果,但實際情況並非如此。本文將分析在web服務器處理請求的過程中,Varnish能起到什麼作用。

web服務器的實現千差萬別,但典型的處理過程是相同的,都要經過一系列的步驟來處理接收到的每個請求。有可能需要啟動一個進程來處理請求,有可能需要從磁盤上載入文件,或者啟動內部線程來編譯執行一些腳本。在執行腳本的過程中,還會有進行很多別的動作,比如進行數據庫查詢,讀取文件等等。當成百上千個請求並發訪問時,服務器的負載會很快上升,出現系統資源不夠的情況。一種更糟的情況是,很多請求是重復的,但web服務器無法記住曾經作出的響應,還會重復上面復雜的處理過程。

當把Varnish部署上之後,web請求的處理過程會有一些變化。客戶端的請求將首先被Varnish接受。Varnish將分析接收的請求,並將其轉發到後端的web服務器上。後端的web服務器對請求進行常規的處理,並將依次將處理結果返回給Varnish。

但Varnish的功能並非僅限於此。Varnish的核心功能是能能將後端web服務器返回的結果緩存起來,如果發現後續有相同的請求,Varnish將不會將這個請求轉發到web服務器,而是返回緩存中的結果。這將有效的降低web服務器的負載,提升響應速度,並且每秒可以響應更多的請求。Varnish速度很快的另一個主要原因是其緩存全部都是放在內存裡的,這比放在磁盤上要快的多。諸如此類的優化措施使得Varnish的相應速度超乎想象。但考慮到實際的系統中內存一般是有限的,所以需要手工配置一下緩存的空間限額,同時避免緩存重復的內容。

下面來看一下Varnish的安裝過程。可以從源碼進行安裝,也可以直接使用一些發行版中的預編譯包。當期Varnish的版本是3.0.3(譯者注:目前最新是2013年6月17日發布的3.0.4版),本文將基於3.0.3進行源碼安裝。需要注意的是,2.X版的Varnish和3.X的配置文件格式發生了變化。可以從Varnish的官方網站上找到2.x到3.x升級的細節。

從源碼進行安裝經常遇到的問題是系統缺少某些依賴的文件。可以從Varnish的安裝文檔裡找到編譯所需的所有依賴的文件。

以root身份運行如下命令來下載和安裝Varnish。
cd /var/tmp
wget http://repo.varnish-cache.org/source/varnish-3.0.3.tar.gz
tar xzf varnish-3.0.3.tar.gz
cd varnish-3.0.3
sh autogen.sh
sh configure
make
make test
make install

Vanish將安裝在/usr/local目錄下。主程序的完整路徑為:/usr/local/sbin/varnishd,默認的配置文件為:/usr/local/etc/varnish/default.vcl

在運行varnishd之前,需要先配置後端的web服務器,參照如下格式編輯default.vcl文件,更改為你自己web服務器配置。
backend default {
    .host = "127.0.0.1";
    .port = "80";
}

用如下命令啟動Varnishd:
/usr/local/sbin/varnishd -f /usr/local/etc/varnish/default.vcl 
 ↪-a :6081 -P /var/run/varnish.pid -s malloc,256m

執行完畢後,Varnish將進入後台運行,同時返回命令行狀態。需要注意的是,Varnish運行時會同時啟動兩個進程,一個主進程,一個是子進程,如果子進程出現問題,主進程將重新生成一個子進程。
 
Varnishd 的啟動選項
  • -f : 指定配置文件位置
  • -a : varnish監聽的本地地址和端口。
  • -P :PID文件位置,用來關閉Varnish
  • -s :cache配置。默認使用256M內存

如果從一些包管理器來安裝varnish,可能安裝完畢後就會自動運行。這種情況下需要先停掉它。並使用上述命令選項來運行。否則一些配置可能和本文例子中的不同了。可以用下面的命令來檢查varnish的運行情況和配置。
/usr/bin/pgrep -lf varnish

啟動完畢之後,Varnish就可以處理並轉發請求了。在轉發過程中,varnish會盡可能的緩存結果。我們通過下面幾個簡單的GET請求,來看看varnish是如何工作的。首先,運行如下命令:
/usr/local/bin/varnishlog
/usr/local/bin/varnishstat

下面的GET命令是perl的libwww-perl中的。使用這個命令可以看到varnish返回的HTTP響應的細節。如果你的系統裡沒有安裝libwww-perl,也可以使用Firefox中live HTTP Headers擴展,或者使用其他類似工具也可以。
GET -Used http://localhost:6081/

在這裡GET命令的選項無所謂。需要注意的是varnish返回的響應,varnish會增加三個相應頭信息,分別是“X-Varnish”、 “Via”和“Age”。這些頭信息在Varnish的處理過程中非常有用。X-Varnish頭信息的後面會有一個或兩個數字,如果是一個數字,就表明 varnish在緩存中沒有發現這個請求,這個數字的含義是varnish為這個請求所做的標記ID。如果X-Varnish後是兩個數字,就表明 varnish在緩存中命中了這個請求,第一個數字是請求的標識ID,第二個數字是緩存的標識ID。“Via”頭信息表明這個請求將經過一個代理。 “Age”頭信息標識出這個請求將被緩存多長時間(單位:秒)。首次請求的“Age”為0,後續的重復請求將會使Age值增大。如果後續的請求沒有是 “Age”增加,那就說明varnish沒有緩存這個響應的結果。

現在來看看 varnishstat 命令啟動執行的情況,如下圖所示:

圖2. varnishstat 命令


最重要的是 cache_hit 和 cache_miss 這兩行。如果沒有任何命中,cache_hits 不會顯示。當越來越多的請求進來,計數器會不斷更新以反應新的命中數和未命中數。

接下來看看 varnishlog 命令:

圖3. varnishlog 命令

上圖顯示varnish接受請求並作出響應的內部細節,下面是varnish官方文檔中的解釋:

第一列是一個亂數,用來標識當前請求。第一列數字相同的行屬於一HTTP請求序列。第二列是日志信息的標簽,所有的日志信 息會分類標記,以“Rx”開頭的為接收的數據,以“Tx”開頭的為發送的數據。第三列表示數據在客戶端,vainish和web服務器之間的傳輸狀態。第 四列是被日志記錄的數據。

varnishlog命令有很多的選項可以在查詢時使用。強烈推薦在排錯或測試時使用varnishlog。可以閱讀varnish的man page來查看這個命令的詳細使用情況。下面是一些使用的例子。

顯示varnish和客戶端之間的通信(忽略後端web服務器):

/usr/local/bin/varnishlog -b


顯示varnish接收到的HTTP頭信息(既有客戶端請求的,也有web服務器響應的):

/usr/local/bin/varnishlog -c -i RxHeader


只顯示web服務器響應的頭信息:

/usr/local/bin/varnishlog -Dw /var/log/varnish.log


從/var/log/varnish.log中讀取所有日志信息

kill `cat /var/run/varnish.pid`


這個命令會從/var/run/varnish.pid中讀取varnish的主進程的PID,並給這個進程發送TERM信號,從而關閉varnish。

現在通過上述命令,我們可以控制varnish的啟動和關閉,可以檢查緩存的命中情況,下一個問題是varnish到底緩存了什麼,會存多久?

varnish的默認緩存策略是偏向保守的(可以通過配置改變)。它默認只緩存get請求和HEAD請求。不會緩存帶有Cookie和認證信息的請 求,也不會緩存帶有Set-Cookie或者有變化的頭信息的響應。varnish也會檢查請求和響應中的Cache-Control頭信息,這個頭信息 中會包含一些選項來控制緩存行為。當Cache-control中Max-age的控制和默認策略沖突時,varnish不會單純的根據Cache- control信息就改變自己的緩存行為。例如:Cache-Control: max-age=n,n為數字,如果varnish收到web服務器的響應中包含max-age,varnish會以此值設定緩存的過期時間(單位: 秒),否則varnish將會設置為參數配置的時間,默認為120秒。

注意:
varnish的默認配置可以適應多數情況。例如,默認的default_ttl緩存過期時間是120秒。配置文件的詳細解釋可以閱讀 varnishd的man page。如果你想改變某些默認設置,一種方式是通過命令行varnishd加上-p參數,這將重啟varnishd,並清空緩存。另外一種方式是使用 varnish的管理接口,要使用varnish的管理接口需要以-T參數啟動varnish,這個參數指定了,varnish管理接口的監聽端口。然後 使用varnishadm命令連接到varnish的管理接口上,然後實時的查詢varnish的運行參數,或者更改新的參數,這些都不需要重啟 varnish。

想要了解詳細的情況,可以參閱varnishd、varnishadm和varnish-cli的man page。

一般情況下我們會改變varnish的緩存行為,定制自己的緩存策略。可以將配置寫入默認的default.vcl文件,VCL是varnish的配置文件的格式,像一種簡單的腳本語言。可以通過vcl的man page來了解詳細的格式,推薦閱讀。

在修改default.vcl配置之前,我們先來看一下varnish處理http請求的一個完整過程。我們將之成為一個請求/響應周期 (request/response cycle)。這個過程始於varnish收到客戶端的請求,varnish將檢查這個請求,並將其標記存儲,接下來varnish將根據一定的策略決定 是將這個請求直接轉發,還是檢查緩存。如果是第一種情況,varnish會將請求直接轉發到後端的服務器上,並且將服務器的響應返回給你客戶端。如果是第 二種情況,varnish會進行一個緩存查詢的過程,如果緩存命中,varnish會將緩存中結果返回給客戶端,如果緩存中沒有,varnish會將此請 求轉發給後端的服務器,並將服務器的響應先進行緩存,然後再轉發給客戶端。

了解完varnish對請求和響應處理的過程之後,我們來討論一下如何改變varnish的緩存策略。varnish有一系列的子功能來完成上述處 理過程,每一個子功能完成處理過程的一個部分。每一個子功能的執行結果傳遞給下一個子功能。所以我們可以通過改變子功能的返回值來改變varnish的處 理動作。每一個子功能都在default.vcl中有一個默認定義,可以通過改變這些值來定制varnish的功能。

Varnish 子程序
varnish的子程序在default.vcl中有默認的配置,如果你重新配置了某一個功能,並不意味著默認的動作一定不會執行。一般情況下,如 果你重新配置了某一個功能,但是沒有返回值,varnish將會執行默認的動,因為所有的varnish子程序都會有一個返回值。這可以看作 varnish的一種容錯機制。

第一個子程序是“vcl_recv”,在姐收到完整的客戶端請求後開始執行這個子程序,可以通過修改req對象來改變默認的請求處 理,varnish根據返回值決定處理方式。比如,返回:pass,將使varnish直接轉發請求到web服務器,返回:lookup,將使 varnish檢查緩存。

下一個子程序是vcl_pass。如果在vcl_recv中返回了“pass”,將執行vcl_pass。vcl_pass有兩種返回值,pass:繼續轉發請求到後端web服務器。restart:將請求重新返回給vcl_recv。

vcl_miss和vcl_hit將會根據varnish的緩存命中情況來執行。vcl_miss的執行有兩種情況,一是從後端服務器獲取響應結 果,並且在本地緩存(fetch),二是從後端獲取到響應,但本地不緩存(pass)。如果varnish緩存命中,將會執行vcl_hit,會有兩個選 擇,一個直接將緩存的結果返回給客戶端(deliver),二是丟棄緩存,重新從後端服務器獲取數據(pass)。

當從後端服務器獲取到數據之後,將會執行vcl_fetch過程,在這裡可以通過beresp對象來訪問響應數據,返回兩種處理結果;deliver:按計劃將數據發送給客戶端,restart,退回這個請求。

在vcl_deliver子程序中,可以將響應結果發送給客戶端(deliver),結束這個請求,同時根據不同情況決定是否緩存結果。也可以返回“restart”值,來重新開始這個請求。

如前所述,通過default.vcl來控制varnish的緩存策略,通過子程序的返回值來控制varnish的動作。子程序的返回值可以基於 req和resp對象,也可以基於客戶端對象,服務端對象或者後端服務器對象。但在子程序處理過程中,上述數據對象並非一直都可用。另外要注意子程序的返 回值會有一定的限制范圍,一個難點就是記住在什麼時候,哪個子程序中什麼數據對象是可用的,合法的返回值有哪些。為了讓這個問題更清晰一些,下面是一張表 格,可以在修改配置的時候快速參考:

表1. 各子程序中各數據對象的可用情況.

  client server req bereq beresp resp obj vcl_recv X X X         vcl_pass X X X X       vcl_miss X X X X       vcl_hit X X X       X vcl_fetch X X X X X     vcl_deliver X X X     X  


表2. 各子程序的合法返回值.

  pass lookup error restart deliver fetch pipe hit_for_pass vcl_recv X X X       X   vcl_pass X   X X         vcl_lookup                 vcl_miss X   X     X     vcl_hit X   X X X       vcl_fetch     X X X     X vcl_deliver     X X X      


注意:
請仔細閱讀vcl的文檔來了解相關子程序,返回值以及可用的數據對象。

下面是一些實際的例子:
修改HTTP請求的 Host 頭信息:

sub vcl_recv {
    if (req.http.host ~ "^www.example.com") {
        set req.http.host = "example.com";
    }
}


你可以通過 req.http.host來訪問請求的HTTP host頭信息,類似的,你可以通過req.http訪問所有的HTTP頭信息。“~”符表示相等的意思,後面是一個正則表達式. 如果匹配上,會通過set關鍵字和“=”賦值操作,將hostname改為"example.com".修改hostname的一個作用是防止重復的緩 存。 因為varnish會通過hostname和URL來判斷緩存匹配情況,所以hostname應該被修改為統一的形式。

下面是默認 vcl_recv 子程序的一個片段:

sub vcl_recv {
    if (req.request != "GET" && req.request != "HEAD") {
        return (pass);
    }
    return (lookup);
}


這是默認的vcl_recv配置文件的片段,在這個配置中如果發現請求不是GET或者HEAD,varnish將會直接pass這個請求,並且不會緩存這個請求的響應,如果是GET或HEAD,將會到緩存中進行查找。

匹配特定的URL,移除請求中的Cookie信息:

sub vcl_recv {
    if (req.url ~ "^/images") {
        unset req.http.cookie;
    }
}


這個是varnish網站上的例子,如果發現請求的URL以"/images"開始,varnish會將其中的Cookie信息移除。當在cookie中設置不緩存當前響應時,varnish可以通過移除Cookie,來緩存這個響應。

在對圖片文件的響應頭中中移除set-Cookie:

sub vcl_fetch {
    if (req.url ~ ".(png|gif|jpg)$") {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1h;
    }
}


這個是varnish網站上的另一個例子。接收到web服務器的返回結果後會觸發vcl_fetch處理過程。當從web服務器接收到新的數據 後,beresp中保存web服務器返回的響應信息,req中是本次請求的信息。如果本次請求的文件是圖像文件,varnish會將響應頭信息中的 “Set-Cookie”移除,並且將緩存的時間設置為1小時(帶有Set-Cookie的響應,varnish不會緩存)。

現在我們想朝響應信息中增加一個"X-Hit"的頭信息,當緩存命中的時候,這個值為1,未命中的時候為0。根據上文,判斷緩存命中的最簡單的辦法 是在vcl_hit中。當緩存命中是會調用vcl_hit,因此可以考慮在vcl_hit中設置這個頭信息,但從上文表1中我們看到,vcl_hit裡 beresp和resp都是不可用的。一個可行的辦法就是在請求中設置裡一個臨時頭信息,然後在後續的處理過程中真正進行設置。下面我們看一下這個問題是 如何解決的:

在響應頭信息中增加“x-hit”:

sub vcl_hit {
    set req.http.tempheader = "1";
}

sub vcl_miss {
    set req.http.tempheader = "0";
}

sub vcl_deliver {
    set resp.http.X-Hit = "0";
    if (req.http.tempheader) {
        set resp.http.X-Hit = req.http.tempheader;
        unset req.http.tempheader;
    }
}


上述vcl_hit和vcl_miss中設置了一個臨時的請求頭信息,來標識出緩存的命中情況。真正的處理過程在vcl_deliver裡,首先默 認設置x-hit為0,然後根據請求裡的臨時頭信息判斷緩存的命中情況,並且依此更新剛才設置的x-hit默認值,最後刪除此臨時頭信息。之所以選擇在 vcl_deliver裡來進行處理,是因為在響應信息返回給客戶端之前,只有在vcl_deliver中才可以訪問resp對象。

下面我們看一個針對此問題錯誤的解決辦法:
增加“x-hit”頭信息(錯誤的方法):

sub vcl_hit {
    set req.http.tempheader = "1";
}

sub vcl_miss {
    set req.http.tempheader = "0";
}

sub vcl_fetch {
    set beresp.http.X-Hit = "0";
    if (req.http.tempheader) {
        set beresp.http.X-Hit = req.http.tempheader;
        unset req.http.tempheader;
    }
}


在vcl_fetch裡修改服務器返回的信息(beresp),但這並不是最終發送給客戶端的數據。上述配置貌似正確,其實隱含了一個大BUG。首 次請求當緩存未命中時,web服務器的響應被標上'x-hit'為0,然後送到vcl_fetch處理,並被緩存在本地。但當後續請求緩存命中 時,vcl_fetch過程不會被執行,結果就導致所有的緩存命中的響應都帶有x-hit=0的標記。這是在配置varnish時需要特別注意的一類問 題。

避免這些問題的辦法是熟練掌握上述的表1的內容,並且在實際工作中多做測試。

下面的配置可以讓varnish將所有的數據緩存一個小時(不建議在真實環境中使用)

sub vcl_recv {
    return (lookup);
}

sub vcl_fetch {
    set beresp.ttl = 1h;
    return (deliver);
}


在上述配置中重寫了vcl_recv和vcl_fetch兩個過程。需要注意的是:如果vcl_fetch不返回“deliver”,varnish將會繼續執行默認的處理過程,就不會有想要的效果了。

一旦varnish運行生效之後,你可以通過一些負載測試工具來測試性能的改善。我通常使用的測試工具是apache自帶的ab,可以從apache的安裝包裡找到,或者通過一些第三方的包管理器進行安裝。可以在apache的網站上找到ab的使用文檔。

在下面的測試例子中,apache2.2監聽在80端口,varnish監聽在6081端口。用來做測試的頁面是一個非常簡單的perl CGI腳本,只輸出一個單行的HTML文件。通過訪問相同的URL來測試apache和varnish的不同表現。為避免網絡因素的影響,所有的測試都在 本機執行。測試中使用的ab選項非常簡單,也可以試著去改變這些選項,看看是什麼結果。

首先進行一個1000次的請求(n=1000),並發數量1個(c=1).

先測試apache:

ab -c 1 -n 1000 http://localhost/cgi-bin/test

 

圖 4. Apache測試結果

再測試varnish:

ab -c 1 -n 1000 http://localhost:6081/cgi-bin/test

圖 5. varnish測試結果


ab的測試輸出裡包含很多信息,最基本的性能指標有“Time per request”和“Requests per second(rps)”。
從上述測試結果來看,apache的每個請求在1ms以上(780rps),而varnish在0.1ms(7336rps)比apache高了10倍。
從這個測試結果說明varnish的速度比apache快,至少在當前環境下是這樣。可以嘗試改變ab的選項來進行不同的測試,例如改變並發訪問數量。

系統負載和磁盤IO( %iowait)
系統負載是反映CPU運行狀況的指標,通常情況下系統中每個CPU核心的負載應該在1.0以下。如果你的系統中有4個CPU核心,理想的系統負載應該在4.0以下。

磁盤的%iowait反映每個CPU時間片內系統的輸入輸出(I/O)狀況。%iowait指標較高表示磁盤IO成為了系統瓶頸會拖慢整體的速度。比如,如果收到的每個請求都需要讀取100個文件或者更多,這將會導致%iowait迅速升高然後成為系統性能的瓶頸。

測試的時候除了關注系統的響應時間之外,還要看系統資源的使用情況。當測試請求持續很長時間時,我們比較一下兩者的系統資源使用情況。監控的指標就 是系統的負載(system load)和磁盤IO(%iowait)。系統負載可以從top命令裡查看,%iowait可以從iostat命令看到。在測試過程中需要同時關注這兩個 指標,我們打開兩個終端分別運行top和iostat。

運行iostat,2秒更新一次:

iostat -c 2


運行top:

/usr/bin/top


現在就可以做測試了。因為要看長時間持續請求的狀況下服務器的性能表現(至少要在1到10分鐘),所以需要在ab的選項裡加大請求次數和並發數量。

使用ab對Apache進行測試:

ab -c 50 -n 100000 http://localhost/cgi-bin/test

圖 6. Apache 下系統壓力測試流量記錄


使用ab測試Varnish:

ab -c 50 -n 1000000 http://localhost:6081/cgi-bin/test

圖 7. Varnish下系統壓力測試流量記錄


首先對比響應時間,雖然截圖上沒有直接顯示時間,但是我們可以從ab結束的時間計算出來,apache是23ms每次請求 (2097rps),varnish是4ms每次請求(12099rps)。最大的差異是平均負載,Apache使系統的負載達到了12,使用 varnish時則一直保持在0~0.4。在從apache切換到varnish做測試時,甚至要等上幾分鐘,系統負載才能回復正常。最好在非生產環境下 用比較空閒的機器做這些測試。

盡管真實環境中的web服務器有很多個性化的配置和需求,但是vanish一般都可以幫助你的web服務器提高性能並且降低負載。
轉自:http://www.oschina.net/translate/speed-your-web-site-varnish

Copyright © Linux教程網 All Rights Reserved