varnish及其應用(三)

4、fetch子進程

如果收到的後端響應報文的ttl值小於0(失效了),或者響應報文中有Set-cookie首部,或者首部Vary等於“*”,則設定響應報文的ttl值爲120秒,返回關鍵字hit_for_pass進行處理

sub vcl_fetch {
     if (beresp.ttl <= 0s ||
         beresp.http.Set-Cookie ||
         beresp.http.Vary == "*") {
               /*
                * Mark as "Hit-For-Pass" for the next 2 minutes
                */
               set beresp.ttl = 120 s;
               return (hit_for_pass);
     }
     return (deliver);
 }



5移除單個緩存對象:


purge與GET、DEAD一樣,也是一種請求類型,用於清理緩存中的某特定對象及其變種(variants),因此,在有着明確要修剪的緩存對象時可以使用此種方式。HTTP協議的PURGE方法可以實現purge功能,不過,其僅能用於vcl_hit和vcl_miss中,它會釋放內存工作並移除指定緩存對象的所有Vary:-變種,並等待下一個針對此內容的客戶端請求到達時刷新此內容。另外,其一般要與return(restart)一起使用。下面是個在VCL中配置的示例:

先定義一個acl (access control list),將可以做purge的ip地址列入該名單,注意限定網絡的方法;

在vcl_recv中添加條件判斷:不在白名單中的用戶使用了purge則返回錯誤代碼並丟棄該請求,這可以;

如果用戶是允許purge的用戶,且緩衝中有查找的內容,則在vcl_hit中做條件判斷——如果是purge方法,則做相應的移除操作,並返回狀態碼200及原因說明“Purged”;

如果用戶是允許purge的用戶,且緩衝中沒有緩衝內容,則在vcl_miss引擎中做條件判斷——如果是purge方法,則調用purge動作,並返回狀態碼404及原因說明“沒有相應的緩存”;

如果用戶是允許purge的用戶,但傳送到pass引擎了,則返回錯誤代碼502及說明“在錯誤的對象上使用了purge方法”。

這時要注意是否開啓了vcl_recv子進程中關於req.request的設置,如果開啓了,則需在vcl_recv子進程裏添加進允許purege能被引用到hit或miss引擎的機制。

acl purgers {
"127.0.0.1";
"172.16.0.0"/24;
}
sub vcl_recv {
if (req.request == "PURGE") {
if (!client.ip ~ purgers) {
error 405 "Method not allowed";
}
return (lookup);
}
}
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 "PURGE on a passed object";
}
}

wKiom1V0PCXBba6nAAO47xqL_7E812.jpg

wKioL1V0PeOQPWDhAAWhQGNvGYc361.jpg



最終的配置如下:

[root@aunt-s ~]# grep -v "^[[:space:]]*#" /etc/varnish/default.vcl
backend default {
  .host = "172.16.20.150";
  .port = "80";
}
acl purgers {
"127.0.0.1";
"172.16.0.0"/16;
}
 sub vcl_recv {
     if (req.restarts == 0) {
 if (req.http.x-forwarded-for) {
     set req.http.X-Forwarded-For =
 req.http.X-Forwarded-For + ", " + client.ip;
 } else {
     set req.http.X-Forwarded-For = client.ip;
 }
     }
     if (req.request == "PURGE") {
if ( !client.ip ~ purgers ) {
   error 405 "Method not allowed.";
}
     }
     if (req.request != "GET" &&
       req.request != "HEAD" &&
       req.request != "PUT" &&
       req.request != "POST" &&
       req.request != "TRACE" &&
       req.request != "OPTIONS" &&
       req.request != "DELETE" &&
req.request != "PURGE" ) {
         /* Non-RFC2616 or CONNECT which is weird. */
         return (pipe);
     }
     if (req.request != "GET" && req.request != "HEAD" && req.request != "PURGE") {
         /* We only deal with GET and HEAD by default */
         return (pass);
     }
     if (req.http.Authorization || req.http.Cookie) {
         /* Not cacheable by default */
         return (pass);
     }
     return (lookup);
 }
 sub vcl_pass {
    if (req.request == "PURGE") {
error 502 "Purge on a pass object.";
    }
     return (pass);
 }
 sub vcl_hit {
    if (req.request == "PURGE") {
purge;
error 200 "Pureged.";
    }
     return (deliver);
 }
 sub vcl_miss {
    if (req.request == "PURGE") {
purge;
error 404 "Not in cache.";
    }
     return (fetch);
 }
 sub vcl_deliver {
if (obj.hits>0) {
   set resp.http.X-Cache = "HIT";
} else {
   set resp.http.X-Cache = "MISS";
}
     return (deliver);
 }



6、定義要使用的後端主機


(1)backend{} 定義單個後端主機

方法:先用backend NAME{}定義一個後端主機,一個後端主機定義一個backend,有多個後端就用多個backend定義,然後在需要相關的引擎裏的合適位置用if條件判斷引用對應的後端主機。

① node2上配置好php服務:

[root@node2 ~]# yum install -y php
……
Installed:
  php.x86_64 0:5.3.3-38.el6                                                                                               
Dependency Installed:
  php-cli.x86_64 0:5.3.3-38.el6                              php-common.x86_64 0:5.3.3-38.el6                             
Complete!
[root@node2 ~]# vim /var/www/html/index.php
<h1>test page on node2</h1>
<?php
phpinfo();
?>


node1後端主機仍只提供靜態頁面html服務

② 在varnish緩存策略配置文件中定義後臺主機:

backend default {
  .host = "172.16.20.150";
  .port = "80";
}
backend static {
  .host = "172.16.20.150";
  .port = "80";
}
backend appsrv {
  .host = "172.16.20.200";
  .port = "80";
}


上面使用了2個主機,但定義了三個後端,其中一個是動態頁面服務後端,一個靜態頁面服務後端,還有一個是需要作出後端主機選擇而又沒有指定時的默認後端(default)。


③ 在varnish緩存策略配置文件中定義什麼時候調用後端主機:

一般是在vcl.recv子進程中第一個做出return()或者error的if條件判斷語句之前定義即可。

在sub vcl_recv {}中添加如下行,位置如上說明:

sub vcl_recv {
 if (req.url ~ "\.php$") {
            set req.backend = appsrv;
     } else {
            set req.backend = static;
     }
}


④ 使用驗證:

[root@aunt-s ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.load v1 default.vcl
200        
VCL compiled.
varnish> vcl.use v1
200        
varnish>

wKiom1V0PGTyWmpdAALfGZ6nbDc118.jpg


上圖右上角的圖片是靜態頁面,動靜分離後將該圖片對應的地址的調用地址分配到statis主機(node1)上了,但node1上是沒有這個圖片的,所以沒有顯示。

實際應用中將頁面的動態內容和靜態內容分離後,需要做好動態頁面上的靜態內容的絕對路徑重寫到靜態服務器上。

(2)director{} 定義後端主機邏輯組

Varnish中可以使用director{}指令將一個或多個近似的後端主機定義爲一個邏輯組,以邏輯組作爲一個整體接受同一種動作或者提供同一種服務。不同的director可以使用同一個後端主機,而某director也可以使用“匿名”後端主機(在director中直接進行定義)。每個director都必須有其專用名,且在定義後必須在VCL中進行調用,VCL中任何可以指定後端主機的位置均可以按需將其替換爲調用某已定義的director。

調用方法:

在vcl_recv上,一般用

set req.backend = DIRECTOR


在邏輯組內可以指定調度方式(也叫挑選方法)來輪流將請求發送至這些主機上。Varnish的director支持的挑選方法中比較簡單的有round-robin和random兩種。其中,round-robin類型沒有任何參數,只需要爲其指定各後端主機即可,挑選方式爲“輪叫”,並在某後端主機故障時不再將其視作挑選對象;random方法隨機從可用後端主機中進行挑選,每一個後端主機都需要一個.weight參數以指定其權重(僅能用於random模式必須使用.weight;round-robin必不能用.retries和.weight)。

Varnish 2.1.0後,random挑選方法又多了兩種變化形式client和hash。client類型的director使用client.identity作爲挑選因子,這意味着client.identity相同的請求都將被髮送至同一個後端主機。client.identity默認爲client.ip,但也可以在VCL中將其修改爲所需要的標識符。類似地,hash類型的director使用hash數據作爲挑選因子,這意味着對同一個URL的請求將被髮往同一個後端主機,其常用於多級緩存的場景中。然而,無論是client還hash,當其傾向於使用後端主機不可用時將會重新挑選新的後端其機。

同時還可以director級別使用.retries參數來設定查找一個健康後端主機時的嘗試次數。

另外還有一種稱作fallback的director,用於定義備用服務器,如下所示:


director b3 fallback {

  { .backend = www1; }

  { .backend = www2; } // will only be used if www1 is unhealthy.

  { .backend = www3; } // will only be used if both www1 and www2

                       // are unhealthy.

}


實操:

[root@aunt-s ~]# vim  /etc/varnish/default.vcl
probe healthchk {
   .url = "/index.html";
   .window = 5;
   .threshold = 3;
   .interval = 3s;
   .timeout = 1s;
   .initial = 3;
   .expected_response = 200;
}
backend default {
  .host = "172.16.20.150";
  .port = "80";
  .probe = healthchk;
}
backend appsrv {
  .host = "172.16.20.200";
  .port = "80";
  .probe = {
        .url = "/index.php";
        .window = 5;
        .threshold = 3;
        .interval = 3s;
        .timeout = 1s;
        .expected_response  = 200;
  }
}
director mystaticsrv round-robin {
#   .retries = 3;
   {
        .backend = appsrv;
#        .weight = 1;
   }
   {
        .backend = {
        .host = "172.16.20.150";
        .port = "80";
        }
#        .weight = 2;
   }
}
acl purgers {
        "127.0.0.1";
        "172.16.0.0"/16;
}
 sub vcl_recv {
   ……
   
     if (req.url ~ "/index.html") {
        return(pass);
     }
     if (req.url ~ "\.php$") {
            set req.backend = appsrv;
     } else {
            set req.backend = mystaticsrv;
     }
……


[root@aunt-s ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.load v7 default.vcl
200        
VCL compiled.
varnish> vcl.use v7
200



如上示例中,web1爲顯式定義的後端主機,而webservers這個directors還包含了一個“匿名”後端主機(backweb2.magedu.com)。webservers從這兩個後端主機中挑選一個主機的方法爲round-robin。


但是,此設置無論怎麼刷新,都只能定位到一個後端服務器上,修改爲random模式後還是隻能定位到一個主機上。

解決辦法:調整sub vcl_recv代碼如下

 

sub vcl_recv {
   ……
   
     if (req.url ~ "\.php$") {
            set req.backend = appsrv;
     } else {
            set req.backend = mystaticsrv;
     if (req.url ~ "/index.html") {
        return(pass);
     }
     }
……


wKiom1V0PI3xqKaJAAKKb-G4Ccg541.jpg




7、後端服務器健康狀態監測


Varnish可以檢測後端主機的健康狀態,在判定後端主機失效時能自動將其從可用後端主機列表中移除,而一旦其重新變得可用還可以自動將其設定爲可用。爲了避免誤判,Varnish在探測後端主機的健康狀態發生轉變時(比如某次探測時某後端主機突然成爲不可用狀態),通常需要連續執行幾次探測均爲新狀態纔將其標記爲轉換後的狀態。


每個後端服務器當前探測的健康狀態探測方法通過.probe{}進行設定,其結果可由req.backend.healthy變量獲取,也可通過varnishlog中的Backend_health查看或varnishadm的debug.health查看。


定義方式有兩種:

方法一:先定義.probe{}檢測方法,然後在 設定主機backend{}或者director{}時調用;

方法二:直接在設定主機backend{}時定義該主機的檢測方法

在配置文件中按如下設置,其他設置不變:

[root@aunt-s ~]# vim  /etc/varnish/default.vcl
probe healthchk {
   .url = "/index.html";
   .window = 5;
   .threshold = 3;
   .interval = 3s;
   .timeout = 1s;
   .initial = 3;
   .expected_response = 200;
}
backend default {
  .host = "172.16.20.150";
  .port = "80";
  .probe = healthchk;
}
backend static {
  .host = "172.16.20.150";
  .port = "80";
  .probe = healthchk;
}
backend appsrv {
  .host = "172.16.20.200";
  .port = "80";
  .probe = {
        .url = "/index.php";
        .window = 5;
        .threshold = 3;
        .interval = 3s;
        .timeout = 1s;
        .expected_response  = 200;
  }
}



[root@aunt-s ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.load v2 default.vcl
200        
VCL compiled.
varnish> vcl.use v2
200        
varnish> backend.list
200        
Backend name                   Refs   Admin      Probe
default(172.16.20.150,,80)     3      probe      Healthy 5/5
static(172.16.20.150,,80)      2      probe      Healthy 5/5
appsrv(172.16.20.200,,80)      2      probe      Healthy 5/5



同時在後端服務器上可以看到健康檢測的日誌記錄


[root@node2 ~]# tail -3 /var/log/httpd/access_log
172.16.20.100 - - [07/Jun/2015:11:41:36 +0800] "GET /index.php HTTP/1.1" 200 43293 "-" "-"
172.16.20.100 - - [07/Jun/2015:11:41:39 +0800] "GET /index.php HTTP/1.1" 200 43293 "-" "-"
172.16.20.100 - - [07/Jun/2015:11:41:42 +0800] "GET /index.php HTTP/1.1" 200 43293 "-" "-"



必要時應該在後端主機上關閉健康檢測的日誌記錄。


將主頁換名,查看檢測是否正常工作:

[root@node2 ~]# mv /var/www/html/index.php /var/www/html/index.php.bak


wKioL1V0PmORNukbAAGe68gYH50660.jpg


[root@node2 ~]# mv /var/www/html/index.php.bak /var/www/html/index.php


wKioL1V0PnLx_er7AAGnimP2oWs089.jpg




8、案例說明:

# Drop any cookies sent to Wordpress.

sub vcl_recv {

if (!(req.url ~ "wp-(login|admin)")) {

unset req.http.cookie;

}

}

說明:當請求報文中沒匹配到 "wp-login"或 "wp-admin"(即登錄或管理時發的請求報文)時,撤銷請求報文首部中的cookie信息。

意義:用戶登錄後與服務器建立連接,派發cookie後,每次發過來的請求報文都有cookie信息,而一般情況下,含cookie首部的報文是不緩存的,這樣大大影響響應速率增加後端服務器的壓力,撤銷cookie首部後就能緩存報文body了。

sub vcl_recv {

 if (req.http.host ~ "(?i)^(www.)?doco.com$") {

   set req.http.host = "www.doco.com";

   set req.backend = www;

 } elsif (req.http.host ~ "(?i)^images.doco.com$") {

   set req.backend = images;

 } else {

   error 404 "Unknown virtual host";

 }

}

說明:如果發送請求報文首部中指定的服務器主機名爲“www.doco.com”或“doco.com”(忽略大小寫),則設定req.http.host的值爲 “www.doco.com” ,同時設定名爲www服務器作爲相應的後端服務器;

如果發送請求報文首部中指定的服務器主機名爲 "images.doco.com"(忽略大小寫),則設定後端服務器爲images服務器;

其他請求報文中服務器主機名爲其他情況時,返回錯誤結果,響應碼404,原因說明“未知的虛擬主機”








參考:

https://www.varnish-cache.org/docs/3.0/reference/vcl.html#varnish-configuration-language


http://baike.baidu.com/link?url=fYBhU6x-FvtcasMLTvT-J3EgSwnf6XKmHu1vw0FAxB73__BpSDdg6G72qKn5gxBzQsfvNADwoPfymuEgS8Ssva





抽風


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