Varnish介紹,安裝與配置詳解。

一、Varnish 簡介

        Varnish是一款高性能的開源HTTP加速器,挪威最大的在線報紙 Verdens Gang 使用3臺Varnish代替了原來的12臺Squid,性能比以前更好。


        Varnish 的作者Poul-Henning Kamp是FreeBSD的內核開發者之一,他認爲現在的計算機比起1975年已經複雜許多。在1975年時,儲存媒介只有兩種:內存與硬盤。但現在計算 機系統的內存除了主存外,還包括了CPU內的L1、L2,甚至有L3快取。硬盤上也有自己的快取裝置,因此Squid Cache自行處理物件替換的架構不可能得知這些情況而做到最佳化,但操作系統可以得知這些情況,所以這部份的工作應該交給操作系統處理,這就是 Varnish cache設計架構。


        Varnish 項目是2006年發佈的第一個版本0.9.距今已經八年多了,此文檔之前也提過varnish還不穩定,那是2007年時候編寫的,經過varnish開 發團隊和網友們的辛苦耕耘,現在的varnish已經很健壯。很多門戶網站已經部署了varnish,並且反應都很好,甚至反應比squid還穩定,且效 率更高,資源佔用更少。相信在反向代理,web加速方面,varnish已經有足夠能力代替squid。


二、Varnish狀態引擎


wKiom1PxZorS50Y_AAMZtFoJlSU676.jpg

  • Receive狀態,也就是請求處理的入口狀態,根據VCL規則判斷該請求應該Pass或Pipe,還是進入Lookup(本地查詢)。

  • Lookup狀態,進入此狀態後,會在hash表中查找數據,若找到,則進入Hit狀態,否則進入miss狀態。

  • Pass狀態,在此狀態下,會進入後端請求,即進入Fetch狀態。

  • Fetch狀態,在Fetch狀態下,對請求進行後端獲取,發送請求,獲得數據,是否進行本地存儲。

  • Deliver狀態, 將獲取到的數據發送給客戶端,然後完成本次請求。

  • pipe狀態時,請求直接傳遞至後端主機,在請求和返回的內容沒有改變的情況下,將不變的內容返回給客戶端,直到這個鏈接被關閉。

三、內置公用變量

VCL內置的公用變量可以用在不同的VCL函數中。下面根據這些公用變量使用的不同階段依次進行介紹。

(1).當請求到達後,可以使用的公用變量

  • req.backend 指定對應的後端主機

  • server.ip 表示服務器端IP

  • client.ip 表示客戶端IP

  • req.request 指定請求的類型,例如GET、HEAD和POST等

  • req.url 指定請求的地址

  • req.proto 表示客戶端發起請求的HTTP協議版本

  • req.http.header 表示對應請求中的HTTP頭部信息

  • req. restarts ;/.l表示請求重啓的次數,默認最大值爲4

(2).Varnish在向後端主機請求時,可以使用的公用變量

  • beresp.request 指定請求的類型,例如GET合HEAD等

  • beresp.url 指定請求的地址

  • beresp .proto 表示客戶端發起請求的HTTP協議版本

  • beresp .http.header 表示對應請求中的HTTP頭部信息

  • beresp .ttl 表示緩存的生存週期,也就是cache保留多長時間,單位是秒

(3).從cache或後端主機獲取內容後,可以使用的公用變量

  • obj.status 表示返回內容的請求狀態代碼,例如200、302和504等

  • obj.cacheable 表示返回的內容是否可以緩存,也就是說,如果HTTP返回的是200、203、300、301、302、404或410等,並且有非0的生存期,則可以緩存

  • obj.valid 表示是否是有效的HTTP應答

  • obj.response 表示返回內容的請求狀態信息

  • obj.proto 表示返回內容的HTTP協議版本

  • obj.ttl 表示返回內容的生存週期,也就是緩存時間,單位是秒

  • obj.lastuse 表示返回上一次請求到現在的間隔時間,單位是秒

(4).對客戶端應答時,可以使用的公用變量

  • resp.status 表示返回給客戶端的HTTP狀態代碼

  • resp.proto 表示返回給客戶端的HTTP協議版本

  • resp.http.header 表示返回給客戶端的HTTP頭部信息

  • resp.response 表示返回給客戶端的HTTP狀態信息

在上面的講述中,只介紹了常用的VCL內置公用變量,如果需要了解和使用更多的公用變量信息,請登錄varnish官方網站查閱。https://www.varnish-cache.org/docs/3.0/


四、安裝與基本配置

直接去官網下載rpm包安裝即可。

編輯啓動腳本配置文件  /etc/sysconfig/varnish

NFILES=131072  //定義最大打開文件的數量

MEMLOCK=82000  //定義用於緩存日誌的空間 (KB)

NPROCS="unlimited"  //最大打開的線程數量unlimited(無上限)

RELOAD_VCL=1   //無需重啓服務,可以重新編譯載入VCL

VARNISH_VCL_CONF=/etc/varnish/default.vcl  //規則文件

VARNISH_LISTEN_PORT=80  //服務偵聽端口

VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1  //管理接口偵聽的地址

VARNISH_ADMIN_LISTEN_PORT=6082  //管理端口

VARNISH_SECRET_FILE=/etc/varnish/secret  //密鑰文件

VARNISH_MIN_THREADS=50  //最小線程數

VARNISH_MAX_THREADS=1000  //最大線程數

VARNISH_THREAD_TIMEOUT=120   //線程超時時間

#VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin

#VARNISH_STORAGE_SIZE=1G

VARNISH_MEMORY_SIZE=64M   //使用緩存的內存大小

VARNISH_STORAGE="malloc,${VARNISH_MEMORY_SIZE}" //指定緩存類型,這是是指使用內存緩存。也可以用file指定緩存至磁盤文件上。

VARNISH_TTL=120


DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
             -f ${VARNISH_VCL_CONF} \
             -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
             -t ${VARNISH_TTL} \
             -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
             -u varnish -g varnish \
             -S ${VARNISH_SECRET_FILE} \
             -s ${VARNISH_STORAGE}"


啓動varnish

/etc/init.d/varnish start

連接管理端口,查看管理命令。

varnishadm -S /etc/varnish/secret  -T 127.0.0.1:6082

wKiom1Pxk7PhraNrAAJj-uNDMdA964.jpg

五、配置一個簡單的後端

vim /etc/varnish/default.vcl


backend default {  //定義後端主機。
  .host = "192.168.18.201";
  .port = "80";
}
sub vcl_recv {  //在recv調用。
        set req.backend = default;
}

加載配置文件,使用配置。

varnishadm

vcl.load d2 /etc/varnish/default.vcl

vcl.use d2

測試一下

wKioL1PxmwDgILehAAMDolwntAI368.jpg


已成功代理至後端服務器,但是我們無法查看是否命中,接下來添加配置。

sub vcl_deliver {
        if (obj.hits > 0) {
        set resp.http.X-cache = "Hit from" +" "+server.ip;
         } else {
        set resp.http.X-cache = "Miss var"+" "+server.ip;
        }
}

重新載入文件和上述方法相同(略)

測試效果

wKiom1PxnVqjsWIdAAE2uWkaDvw273.jpg

現在配置不讓它緩存

backend default {
  .host = "192.168.18.201";
  .port = "80";
}
sub vcl_recv {
        if (req.url ~ "\.jsp$") {
          return(pass);
}
        set req.backend = default;
}
sub vcl_deliver {
        if (obj.hits > 0) {
        set resp.http.X-cache = "Hit from" +" "+server.ip;
         } else {
        set resp.http.X-cache = "Miss var"+" "+server.ip;
        }
}
wKioL1PxolfyEHggAAFBny6y72s359.jpg


控制某個目錄下的文件不讓緩存

backend default {
  .host = "192.168.18.201";
  .port = "80";
}
sub vcl_recv {
        if (req.url ~ "^/bbs/" ) {
          return(pass);
}
        set req.backend = default;
}
sub vcl_deliver {
        if (obj.hits > 0) {
        set resp.http.X-cache = "Hit from" +" "+server.ip;
         } else {
        set resp.http.X-cache = "Miss var"+" "+server.ip;
        }
}

上面的所有配置都是根據用戶請求的內容做出決策的,下面我們來配置根據響應的內容做出決策。

定義緩存TTL時間

sub vcl_fetch {
    if (req.request == "GET" && req.url ~ "\.(html|css|js|jpg|jpeg|png|gif)$") {
        set beresp.ttl = 3600s;
    }
}

六、兩臺WEB服務器動靜分離實例
backend web1 {
  .host = "192.168.18.201";
  .port = "80";
}
backend web2 {
  .host = "192.168.18.202";
  .port = "80";
}
sub vcl_recv {

        if (req.url ~ "\.jsp$") {
          set req.backend = web2;
}   else {
          set req.backend = web1;
}
}
sub vcl_fetch {
        if (req.request == "GET" && req.url ~ "\.(html|jpg|jpeg|css|js|bmp|ico|txt)$") {
                set beresp.ttl = 3600s;
}
}

sub vcl_deliver {
        if (obj.hits > 0) {
        set resp.http.X-cache = "Hit from" +" "+server.ip;
         } else {
        set resp.http.X-cache = "Miss var"+" "+server.ip;
        }
}

七、配置健康狀態檢測

.url  //指定檢測的URL

.request 探測後端主機健康狀態時所請求內容的詳細格式,定義後,它會替換.url指定的探測方式;比如:

.request =
  "GET /.healthtest.html HTTP/1.1"
  "Host: www.test.com"
  "Connection: close";

.window   //做健康狀況檢測時,至少要採樣多少次;

.threshold  //在.window中指定的次數中,至少有多少次是成功的才判定後端主機正健康運行;默認是3;

.initial    //Varnish啓動時對後端主機至少需要多少次的成功探測,默認同.threshold;

.expected_response    //期望後端主機響應的狀態碼,默認爲200;
.interval     //探測請求的發送頻率,默認爲5秒;
.timeout    //每次探測請求的過期時長,默認爲2秒;

有兩種定義方式:

1、在backend中使用.probe 定義,例:

backend www {
  .host = "www.tuchao.com";
  .port = "http";
  .probe = {
    .url = "/test.jpg";
    .timeout = 1s;
    .window = 8;
    .threshold = 3;
    .initial = 3;
  }
}

2、可以明確的定義一個公共的probe,在backend中用.probe調用。例:

probe healthchk {
  .url = "/health.html";
  .interval = 2s;
  .timeout = 2s;
  .expected_response = 200;
  .window = 3;
  .threshold = 1;
}
backend web1 {
  .host = "192.168.18.201";
  .port = "80";
  .probe = healthchk;
}
backend web2 {
  .host = "192.168.18.202";
  .port = "80";
  .probe = healthchk;
}

sub vcl_recv {

        if (req.url ~ "\.jsp$") {
          set req.backend = web2;
}   else {
          set req.backend = web1;
}
}
sub vcl_fetch {
        if (req.request == "GET" && req.url ~ "\.(html|jpg|jpeg|css|js|bmp|ico|txt)$") {
                set beresp.ttl = 3600s;
}
}

sub vcl_deliver {
        if (obj.hits > 0) {
        set resp.http.X-cache = "Hit from" +" "+server.ip;
         } else {
        set resp.http.X-cache = "Miss var"+" "+server.ip;
        }
}


八、負載均衡的實現

調度算法:

random   //根據權重隨機調度

hash    //將同一個請求發往同一個主機


配置實例:

probe healthchk {
  .url = "/health.html";
  .interval = 2s;
  .timeout = 2s;
  .expected_response = 200;
  .window = 3;
  .threshold = 1;
}
backend web1 {
  .host = "192.168.18.201";
  .port = "80";
  .probe = healthchk;
}
backend web2 {
  .host = "192.168.18.202";
  .port = "80";
  .probe = healthchk;
}
director webs random {     //定義集羣,定義調度算法。
        .retries = 2;
        {
                .backend = web1;
                .weight = 1;
        }
        {
                .backend = web2;
                .weight = 1;
        }
}

sub vcl_recv {
        set req.backend = webs;
}
sub vcl_fetch {
        if (req.request == "GET" && req.url ~ "\.(html|jpg|jpeg|css|js|bmp|ico|txt)$") {
                set beresp.ttl = 3600s;
}
}


九、移除單個緩存對象配置實例


probe healthchk {
  .url = "/health.html";
  .interval = 2s;
  .timeout = 2s;
  .expected_response = 200;
  .window = 3;
  .threshold = 1;
}
acl purgers {
        "127.0.0.1";
        "192.168.18.0"/24;
}
backend web1 {
  .host = "192.168.18.201";
  .port = "80";
  .probe = healthchk;
}
backend web2 {
  .host = "192.168.18.202";
  .port = "80";
  .probe = healthchk;
}
director webs hash {
        .retries = 2;
        {
                .backend = web1;
                .weight = 1;
        }
        {
                .backend = web2;
                .weight = 1;
        }
}

sub vcl_recv {
        if (req.request == "PURGE") {
             if (!client.ip ~ purgers) {
                 error 405 "Method not allow";
        }
                return (lookup);
        }
        set req.backend = webs;
}
sub vcl_hit {
        if (req.request == "PURGE") {
                purge;
                error 200 "Purged";
        }
}
sub vcl_miss {
        if (req.request == "PURGE") {
                purge;
                error 404 "Not in cache.";
        }
}
sub vcl_pass {
        if (req.request == "PURGE") {
                error 502 "Purged on a passed object.";
        }
}

測試效果

先訪問一下

wKioL1PyAG_zjX4zAAHuzcV28gk630.jpg


這時執行PURGE清除

wKioL1PyAJyA3_NpAAIAsq6g2Uk384.jpg

再訪問一下

wKioL1PyAMGRQG_JAAG8pweQoPU865.jpg

看,Miss,緩存被成功清除。

十、防盜鏈配置實例

sub vcl_recv {
        if (req.http.referer ~ "http://.*" ) {
                if (!(req.http.referer ~ "http://.*\.tuchao\.com" || req.http.referer ~ "http://.*\.google\.com.*" || req.http.referer ~ "http://.*\.baidu\.com.*" )) {
                set req.http.host = "www.tuchao.com";
                set req.url = "/referer/tuchao.html";
        }
}

        if (req.request == "PURGE") {
             if (!client.ip ~ purgers) {
                 error 405 "Method not allow";
        }
                return (lookup);
        }
        set req.backend = webs;
}

測試結果

wKiom1PyC7DyWtTBAAJ5ZShpzEo655.jpg


這篇就寫到這裏了,總共分了十個章節,希望大家能從中學習到知識。

我掌握的也不牢靠,歡迎大家與我交流QQ1183710107.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章