varnish3.0運維-vcl說明

varnish3.0運維-vcl說明

描述

        VCL是專門爲了varnish定製的特殊範圍語言。

varnish配置文件被重新加載時,varnish的管理進程會依靠vcl重新編譯配置文件,並且會將編譯結果存放在一塊內存中。

語法

        VCL語法其實比較簡單,規則類似cperl;在正則表達式方面,VCL不會讓你失望。在VCL中,已經定義好了幾個函數:

        delivererrorfetchhashhit_for_passlookupokpasspiperestart。下面會說到。

咱們按照Varnish配置文件從上往下依次的介紹。

後端聲明

後端server定義在以關鍵字backend開始的對象中:

backend www {
  .host = "www.example.com";
  .port = "http";
}

當需要調用backend時,你可以寫些個自己的location規則:

if (req.http.host ~ "(?i)^(www.)?example.com$") {
  set req.backend = www;
}

當然了,和其他反向代理一樣,varnish也支持後端健康監測:

backend www {
  .host = "192.168.122.100";
  .port = "80";
  .probe = {
    .url = "/monitor.html";    #健康監測的監控地址
    .timeout = 3s;     #first_byte的超時時間
.interval = 5s;    #檢測間隔時間
.window = 5;       #每次檢測創建5個確認點
.threshold =3;     #有3個確認點ok,就認爲該server ok
    .expected_response = 200;  #健康的標準
  }
}

Directors

你也可以將多個backend放在一個director中:

director b2 random {
  .retries = 5;
  {
    // We can refer to named backends
    .backend = b1;
    .weight  = 7;
  }
  {
    // Or define them inline
    .backend  = {
      .host = "fs2";
    }
  .weight         = 3;
  }
}

Acls

Varnish在做acl時,和nginx類似:

acl local {
  "localhost";         // myself
  "192.0.2.0"/24;      // and everyone on the local network
  ! "192.0.2.23";      // except for the dialin router
}

定義好acl之後,可以這麼調用:

if (client.ip ~ local) {
  return (pipe);
}

函數、子程序

vcl_init

vcl被重新加載時候調用,作用是通知varnish主進程varnish配置文件開始reload的了,需要刷新內存中的配置了。

sub vcl_init {
        return (ok);
}

vcl_recv

在請求開始時調用的。完成該子程序後,請求就被接收並解析了。用於確定是否需要服務請求,怎麼服務,如果可用,使用哪個後端。

recv中,你可以隨意的定製任何組合的匹配規則,在定製規則時,只能對請求對象req做判斷,條件匹配之後,可以用的處理方式有:

pass不做任何緩存,直接轉發
pipe當前client的所有請求varnish不再做處理,直接建立一條該cilent與後端server的“專線”。
lookup:直接從緩存中返回數據。

vcl_pipe

當前client的所有請求varnish不再做處理,直接建立一條該cilent與後端server的“專線”。只能自己調用自己:

sub vcl_pipe {
  return (pipe);
}

vcl_pass

不做任何緩存,直接轉發,可以調用pass或者restart,一般是pass

sub vcl_pass {
  return (pass);
}

vcl_hash

緩存的hash規則。

sub vcl_hash {
  hash_data(req.url);
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }
  return (hash);
}

vcl_hit

命中緩存之後的處理手段。可以調passdeliver

sub vcl_hit {
  if (obj.ttl <= 0s) {
    return (pass);
  }
  return (deliver);    #返回緩存給client。
}

vcl_miss

沒命中。可以調passfetch

sub vcl_miss {
  return (fetch);      #重新去backend獲取數據,之後按照vcl_fetch規則走
}

vcl_fetch

        vcl_fetch是在文檔從後端被成功接收後調用的。通常用於調整響應頭信息,觸發ESI處理,萬一請求失敗就換個後端服務器。在vcl_fecth中,你還可以使用請求對象req。還有個後端響應對象berespBeresp包含了後端的HTTP頭信息。可以調用deliverhit_for_passrestart

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); #類似與pass,但是隻有vcl_fetch可以用。不像pass,hit_for_pass將在緩存中創建一個hitforpass對象。類似個pass的標記。
  }
  return (deliver);
}

vcl_deliver

cache返回client之前的處理過程。

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT from cache.";       #打個標記
    set resp.http.X-Cache-Hits = obj.hits;           #計數器
  } else {
    set resp.http.X-Cache = "MISS from cache.";      #打個標記
  }
  return (deliver);
}

vcl_error

當觸發了一個錯誤(400503等等)或是某些未知的錯誤。

sub vcl_error {
  set obj.http.Content-Type = "text/html; charset=utf-8";
  synthetic {"
  <html>
  <head>
    <title>Page Wrong.</title>
    <style>
      body { background: #efefef; text-align: center; color: white; font-family: Trebuchet MS, sans-serif; }
      #page { width: 500px;margin: 100px auto 0; padding: 30px; background: #888888; border-radius: 14px; -moz-border-radius: 14px; -webkit-border-radius: 14px;border: 0}
      a,a:link,a:visited{color: #cccccc;}
      .error {color: #222222}
      .commany {color: #868686}
    </style>
  </head>
  <body>
    <div id="page">
      <h1>Page Unavailable</h1>
      <p>The page you requested is temporarily unavailable.</p>
      <div>(Error "} + obj.status + " " + obj.response + {")</div>
    </div>
    <div>DangDang Cache Server</div>
  </body>
  </html>
  "};
  return (deliver);
}

vcl_fini

當所有的請求都已經退出完畢時,告訴varnish,可以清空內存數據了。

sub vcl_fini {
        return (ok);
}

對象

VCL中,有三種重要的數據結構。請求:來自客戶端;響應:來自後端服務器;對象:存儲在緩存中。在VCL中你應該知道以下結構:

req:請求對象。當varnish接受了請求,req就會創建並生產。許多在vcl_recv中要做的工作都需要用到req。
beresp:後端響應對象。包含了從後端返回的對象的頭信息。vcl_fetch中,你會使用beresp對象。
obj:緩存了的對象。大多數是駐留在內存中的只讀對象。obj.ttl是可以寫的,剩下的都是隻讀的。

配置示例

# Default backend definition.  Set this to point to your content
# server.
backend dztree {
  .host = "10.64.5.141";
  .port = "80";
  .probe = {
    .url = "/";
    .timeout = 3s;
    .interval = 5s;
    .threshold =8;
  }
}
backend zabbix {
  .host = "172.16.224.23";
  .port = "8801";
  .probe = {
    .url = "/";
    .timeout = 3s;
    .interval = 5s;
    .threshold =8;
  }
}
backend zabbix_self {
  .host = "127.0.0.1";
  .port = "8080";
}
sub vcl_recv {
  #rewrite.
  if (req.url ~ "^/dztree") {
    set req.backend = dztree;
  } elseif (req.url ~ "^/zabbix") {
    set req.backend = zabbix;
  } else {
    set req.backend = zabbix_self;
  }
  #client ip.
  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;
        }
  }
  #Use anonymous, cached pages if all backends are down.
  if (!req.backend.healthy) {
    unset req.http.Cookie;
  }
  #When backend is down, then cache can be use in grace time.
  set req.grace = 10m;
  #do not cache these paths.
  if (req.url ~ "^/admin") {
    return (pass);
  }
  if (req.request != "GET" &&
     req.request != "HEAD" &&
     req.request != "PUT" &&
     req.request != "POST" &&
     req.request != "TRACE" &&
     req.request != "OPTIONS" &&
     req.request != "DELETE") {
     /* Non-RFC2616 or CONNECT which is weird. */
     return (pipe);
  }
  if (req.request != "GET" && req.request != "HEAD") {
     /* 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_pipe {
  return (pipe);
}
sub vcl_pass {
  return (pass);
}
sub vcl_hash {
  hash_data(req.url);
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }
  return (hash);
}
sub vcl_hit {
  if (obj.ttl <= 0s) {
    return (pass);
  }
  return (deliver);
}
sub vcl_miss {
  return (fetch);
}
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);
}
sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT from cache.";
    set resp.http.X-Cache-Hits = obj.hits;
  } else {
    set resp.http.X-Cache = "MISS from cache.";
  }
  return (deliver);
}
sub vcl_error {
  set obj.http.Content-Type = "text/html; charset=utf-8";
  synthetic {"
  <html>
  <head>
    <title>Page Wrong.</title>
    <style>
      body { background: #efefef; text-align: center; color: white; font-family: Trebuchet MS, sans-serif; }
      #page { width: 500px;margin: 100px auto 0; padding: 30px; background: #888888; border-radius: 14px; -moz-border-radius: 14px; -webkit-border-radius: 14px;border: 0}
      a,a:link,a:visited{color: #cccccc;}
      .error {color: #222222}
      .commany {color: #868686}
    </style>
  </head>
  <body>
    <div id="page">
      <h1>Page Unavailable</h1>
      <p>The page you requested is temporarily unavailable.</p>
      <div>(Error "} + obj.status + " " + obj.response + {")</div>
    </div>
    <div>DangDang Cache Server</div>
  </body>
  </html>
  "};
  return (deliver);
}
sub vcl_init {
        return (ok);
}
sub vcl_fini {
        return (ok);
}


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