varnish配置文件VCL详解

关于写varnish的配置文件VCL的相关知识

本文当参考自https://www.varnish-cache.org/docs/3.0/reference/vcl.html#

varnish安装请移步至:

http://blog.csdn.net/cwg_1992/article/details/10728205


首先varnish是一个反向代理缓存服务器,它至少需要一个后端真正的服务器来提供服务此处称之为“后端对象”

首先定义一个后端对象:

backend www {                            //此处backend是关键字声明后端服务器,www是这个后端服务的名字(任意)
  .host = "www.example.com";             //此处可以是域名,也可以是ip地址,也可以是hostname
  .port = "80";                          //后端服务器提供服务的端口
}
定义主机名可以在以后的VCL中选择性的按请求的域名或者hostname来指定相应的后端(这个判断语句在vcl_recv中执行)
例如:

if (req.http.host ~ "(?i)^(www.)?example.com$") {
  set req.backend = www;
}
在为了保证后端的性能,还可以为其设置一些负载控制参数
max_connections:可以设置后端连接的最大并发数目限制。
first_byte_timeout:等待后端返回第一个字节的超时时间。

between_bytes_timeout:接收每一个字节之间的等待时间。

例如:

backend www {
  .host = "www.example.com";
  .port = "http";
  .connect_timeout = 1s;
  .first_byte_timeout = 5s;
  .between_bytes_timeout = 2s;
}


varnish还可以声明一个后端对象的组,可以起到多个后端冗余的作用,varnish可以用不同的算法来确定一次请求具体到那个后端对象上,可以起到负载均衡的作用

例子:

director b2 random {    //director声明这个组的关键字 random是随机模式的组(调度算法),b2是这个组的名字
  .retries = 5;            //每个主机的失败尝试时间
  {
    // We can refer to named backends
    .backend = b1;
    .weight  = 7;                  //这个参数设定了一个后端对象的权重
  }
  {
    // Or define them inline
    .backend  = {
      .host = "fs2";
    }
  .weight         = 3;                //这个参数设定了一个后端对象的权重
  }
}

varnish负载均衡的方式

随机方式:随机抽取后端对象

客户端方式:按客户端的session和cookie来分配后端对象

hash方式:抽取最佳状态的一个后端对象让其出来此次请求的URL

round-robin:加权轮循 和keepalived里的wrr一样

DNS:像dns轮循一样引用一个列表 不支持后端对象的健康测试 开销很大

fallback:类似与故障转移集群 首先将请求交给列表中第一个健康的主机

fallback示例:

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.
}

DNS示例:

director directorname dns {             //组的关键字 组的名字 DNS方式轮循
        .list = {                       //用.list参数配置后端对象
                .host_header = "www.example.com";  //这些后端共用的主机头
                .port = "80";                      //所有的主机都将用80的端口
                .connect_timeout = 0.4s;           //连接超时时间是0.4s
                "192.168.15.0"/24;                 //两个网段,此处的网段不支持IPv6
                "192.168.16.128"/25;               //一共配置384个后端主机 
        }
        .ttl = 5m;                                 //定义DNS lookup的生存期限
        .suffix = "internal.example.net";          //一个标识后拽 这项设置是可选的
}
定义后端时可以设定探测参数

方法一:

backend www {           //定义一个后端对象
  .host = "www.example.com";   //主机名为www.example.com
  .port = "http";              //后端提供服务的端口
  .probe = {                   //定义后端的检测机制
    .url = "/test.jpg";        //探测后端时请求的URL 默认为“/”
    .timeout = 0.3 s;          //超时时间
    .window = 8;               //多少此的探测将确定它是一个健康的后端 默认为8
    .threshold = 3;            //以上windows探测成功后 需要多少次选举 才能定义为
    .initial = 3;
  }
}
方法二(如果有多个后端这个配置可用 减少配置负担):

probe healthcheck {
   .url = "/status.cgi";
   .interval = 60s;
   .timeout = 0.3 s;
   .window = 8;
   .threshold = 3;
   .initial = 3;
   .expected_response = 200;
}

backend www {
  .host = "www.example.com";
  .port = "http";
  .probe = healthcheck;
}
方法三(指定HTTP的请求):

probe rawprobe {
    # NB: \r\n automatically inserted after each string!
    .request =
      "GET / HTTP/1.1"
      "Host: www.foo.bar"
      "Connection: close";
}

一下是probe探测机制所包含的参数与介绍:

.url
Specify a URL to request from the backend.Defaults to "/".
.request
Specify a full HTTP request using multiple strings. .request willhave \r\n automatically inserted after every string.If specified, .request will take precedence over .url.
.window
How many of the latest polls we examine to determine backend health.Defaults to 8.
.threshold
How many of the polls in .window must have succeeded for us to considerthe backend healthy.Defaults to 3.
.initial
How many of the probes are considered good when Varnish starts.Defaults to the same amount as the threshold.
.expected_response
The expected backend HTTP response code.Defaults to 200.
.interval
Defines how often the probe should check the backend.Default is every 5 seconds.
.timeout
How fast each probe times out.Default is 2 seconds.
varnish的ACL(访问控制列表)配置

例子:

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

if (client.ip ~ local) {
  return (pipe);               //如果客户端满足local这个acl,就直接返回pipe
}

Varnish可以使用pcre支持 pcre将为其解析正则表达式

在varnish中正则表达式的使用如果匹配时不考虑大小写可以在匹配的字符前边加上(?i)

例如:

# If host is NOT example dot com..
if (req.http.host !~ "(?i)example.com$") {   //如果请求的主机名不是example.com((?i)是不区分大小写)的主机
        ...
}

Varnish的内置函数:

hash_data(str)
Adds a string to the hash input. In default.vcl hash_data() iscalled on the host and URL of the request.
regsub(str, regex, sub)
Returns a copy of str with the first occurrence of the regularexpression regex replaced with sub. Within sub, \0 (which canalso be spelled \&) is replaced with the entire matched string,and \n is replaced with the contents of subgroup n in thematched string.
regsuball(str, regex, sub)
As regsuball() but this replaces all occurrences.
ban(ban expression)
Bans all objects in cache that match the expression.
ban_url(regex)
Bans all objects in cache whose URLs match regex.
VCL中的程序:

例如:

sub pipe_if_local {
  if (client.ip ~ local) {
    return (pipe);
  }
}
函数调用

vcl_recv函数:

接收和处理请求,当成功接收后被调用,可以通过判断请求的数据来决定如何处理请求。

返回值有如下几种:

error code [reason]:表示返回“code”给客户端,并放弃处理该请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

pass:将请求交给vcl_pass函数处理

pipe:将请求交给vcl_pipe函数处理

lookup:将请求交给vcl_lookup函数处理,然后lookup函数经过判断会将请求交给acl_hit or acl_miss函数进行下一步处理


vcl_pipe函数:

此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个链接关闭。

一般返回值有如下几种:

error code [reason]
pipe


vcl_pass函数:

这种模式下,该请求被传递到后端,后端的响应将被传递给客户端,但还没有进入到高速缓存中。

一般返回值有如下几种:

error code [reason]

pass

restart:重试请求如果重试次数达到max_restart则返回错误


vcl_hash函数:

You may call hash_data() on the data you would like to add to the hash.

The vcl_hash subroutine may terminate with calling return() with one ofthe following keywords:

hash
Proceed.


vcl_hit函数:

在执行lookup指令后,如果在缓存中找到请求的内容,将自动调用该函数。
此函数一般以如下几个关键字结束:
deliver:表示将找到的内容发送给客户端,把请求交给函数vcl_deliver。
error code [reason]
pass


vcl_miss函数:

执行lookup指令后,如果没有在缓存中找到请求的内容时自动调用该方法,此函数可以用于判断是否需要从后端服务器取内容。
此函数一般以如下几个关键字结束:
fetch:表示从后端获取请求的内容,并把请求交给vcl_fetch函数。
error code [reason]
pass


vcl_fetch函数:

在从后端对象成功检索回来一个文件,然后进行其他操作,通过判断获取的内容来决定是否将内容放入缓存,还是直接返回给客户端。

deliver

error code [reason]

hit_for_pass:Pass in fetch. This will create a hit_for_pass object. Note thatthe TTL for the hit_for_pass object will be set to what thecurrent value of beresp.ttl. Control will be handled tovcl_deliver on the current request, but subsequent requests willgo directly to vcl_pass based on the hit_for_pass object.

这将创建一个hit_for_pass对象。
注意,TTL为hit_for_pass对象将被设置为当前值beresp.ttl。
将被处理当前请求vcl_deliver的控制,但后续请求将直接进入以vcl_pass基于hit_for_pass对象。

restart


vcl_deliver函数:

缓存中找到请求的内容后,发送给客户端时(前)调用此函数

返回值有

deliver

restart


vcl_error函数:

当后端返回一个错误时

deliver:将这个错误返回给客户端

restart


VCL也可以在多个配置文件当中配置如下:

# in file "main.vcl"
include "backends.vcl";
include "ban.vcl";

# in file "backends.vcl"
sub vcl_recv {
  if (req.http.host ~ "(?i)example.com") {
    set req.backend = foo;
  } elsif (req.http.host ~ "(?i)example.org") {
    set req.backend = bar;
  }
}

# in file "ban.vcl"
sub vcl_recv {
  if (client.ip ~ admin_network) {
    if (req.http.Cache-Control ~ "no-cache") {
      ban_url(req.url);
    }
  }
}

VCL中可以使用的内置变量

.host:后端的主机名或者ip地址

.port:后端的服务名(例如:http)或者端口号

处理请求时的变量

client.ip:客户端的IP地址

client.identity:在客户端负载均衡模式下,已经存在的客户端(Identification of the client, used to load balance in the client director.)

server.hostname:服务的主机名

server.identity:The identity of the server, as set by the -iparameter. If the -i parameter is not passed to varnishd,server.identity will be set to the name of the instance, asspecified by the -n parameter.

server.ip:The IP address of the socket on which the client connection was received.

server.port:The port number of the socket on which the client connection was received.

req.request:请求类型(例如:"GET", "HEAD")

req.url:所请求的URL

req.proto:客户端所使用的HTTP协议版本

req.backend:使用的后端服务请求(The backend to use to service the request.)

req.backend.healthy:Whether the backend is healthy or not. Requires an active probe to be set on the backend.

req.http.header:HTTP报头

req.hash_always_miss:如果这个值设置为true 则varnish将忽略所有的cache从后端获取而回复这个请求

req.hash_ignore_busy:忽略任何繁忙的对象在缓存中查找。你想要做到这一点,如果你有两个服务器,寻找对方的内容,以避免潜在的死锁

req.can_gzip:客户是否接受gzip的传输

req.restarts:设置重新请求的次数

req.esi:布尔值。设置为false,无论任何beresp.do_esi值禁用ESI处理。默认为true。该变量可以改变

req.esi_level:一个链接中是多少级的ESI请求

bereq.request:被要求(来自客户端的)的请求(be request)类型(e.g. "GET", "HEAD")

bereq.url:被请求(来自客户端的)的URL

bereq.proto:被请求(来自客户端的)到服务器的HTTP版本

bereq.http.header:被请求(来自客户端的)的http头

bereq.connect_timeout:在几秒钟的时间来等待后端连接

bereq.first_byte_timeout:用几秒钟的时间来等待的第一个字节从后端。不适用于pipe模式

bereq.between_bytes_timeout:等待每一个字节的等待时间不能用户pipe模式


以下变量已经从后端检索请求的对象后,方可进入到缓存中 , 他们是提供给vcl_fetch函数使用的

beresp.do_stream:Deliver the object to the client directly without fetching the wholeobject into varnish. If this request is pass'ed it will not bestored in memory. As of Varnish Cache 3.0 the object will marked as busyas it is delivered so only client can access the object.

beresp.do_esi:Boolean. ESI-process the object after fetching it. Defaults tofalse. Set it to true to parse the object for ESI directives. Willonly be honored if req.esi is true.

beresp.do_gzip:将GZIP的对象存储在前边 是一个布尔值,默认是false

beresp.do_gunzip:将没有gzip的对象存储在缓存的前边 布尔值

beresp.http.header:相应的HTTP报头

beresp.proto:后端使用的HTTP协议版本回答

beresp.status:后端应答的状态代码(例如:200,302,404)

beresp.response:由服务器返回的HTTP状态消息(例如:502 bad gateway)

beresp.ttl:后端对象返回的请求内容的生命时间单位为s

beresp.grace:Set to a period to enable grace.

beresp.saintmode:Set to a period to enable saint mode.

beresp.backend.name:Name of the backend this response was fetched from.

beresp.backend.ip:IP of the backend this response was fetched from.

beresp.backend.port:Port of the backend this response was fetched from.

beresp.storage:强制将这个对象保存到一个特定的后端(Set to force Varnish to save this object to a particular storagebackend.)


对象后,输入到缓存中,以下(大多只读)的变量对象已经位于高速缓存中,通常在vcl_hit,构建自定义的错误响应

obj.proto:检索对象时使用的HTTP协议版本

obj.status:检索对象HTTP状态代码

obj.response:检索对象status message

obj.ttl:检索对象的生存时间

obj.lastuse:检索对象最后一次的请求时间 单位是秒 也可有提供给函数vcl_deliver

obj.hits:如果等于0 就说明检索对象没有命中缓存

obj.grace:The object's grace period in seconds. obj.grace is writable.

obj.http.header:检索对象的http报头

一下变量是关于hash key的不作详细介绍贴上原文:

The following variables are available while determining the hash keyof an object:

req.hash
The hash key used to refer to an object in the cache. Used whenboth reading from and writing to the cache.

The following variables are available while preparing a response to the client:

resp.proto
The HTTP protocol version to use for the response.
resp.status
The HTTP status code that will be returned.
resp.response
The HTTP status message that will be returned.
resp.http.header
The corresponding HTTP header.

变量的设置方式  关键字set

例子如下:

sub vcl_recv {
  # Normalize the Host: header
  if (req.http.host ~ "(?i)^(www.)?example.com$") {
    set req.http.host = "www.example.com";       //如果符合一上if的条件 就设置req.http.host的值为www.example.com
  }
}
删除http标头信息可以完全删除使用关键字remove

sub vcl_fetch {
  # Don't cache cookies
  remove beresp.http.Set-Cookie;   //删除beresp.http.Set-Cookie
}
如果后端需要很长的时间来生成一个对象,一个线程堆积起来是有风险的。为了防止这一点,你可以启用例外。这允许版本varnish服务的对象,而正在生成一个的对象由后端。

以下VCL代码将使varnish过期的对象提供服务。所有对象将被保持到两分钟过去他们的到期时间或产生一个新的对象

sub vcl_recv {
  set req.grace = 2m;
}
sub vcl_fetch {
  set beresp.grace = 2m;
}
下面的代码是相当于与后端地址设置为的backend.example.com和指定端口没有后端的默认配置:
backend default {
 .host = "backend.example.com";
 .port = "http";
}
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 != "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 {
    # Note that only the first request to the backend will have
    # X-Forwarded-For set.  If you use X-Forwarded-For and want to
    # have it set for all requests, make sure to have:
    # set bereq.http.connection = "close";
    # here.  It is not set by default as it might break some broken web
    # applications, like IIS with NTLM authentication.
    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 {
    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 {
    return (deliver);
}

sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    set obj.http.Retry-After = "5";
    synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};
    return (deliver);
}

sub vcl_init {
        return (ok);
}

sub vcl_fini {
        return (ok);
}
下面的例子演示了如何在同一varnish实例运行在不同的后端,通过选择基于请求的URL的后端支持多个网站:
backend www {
  .host = "www.example.com";
  .port = "80";
}

backend images {
  .host = "images.example.com";
  .port = "80";
}

sub vcl_recv {
  if (req.http.host ~ "(?i)^(www.)?example.com$") {
    set req.http.host = "www.example.com";
    set req.backend = www;
  } elsif (req.http.host ~ "(?i)^images.example.com$") {
    set req.backend = images;
  } else {
    error 404 "Unknown virtual host";
  }
}
为所有的对象设置最小的TTL缓存
import std; # needed for std.log
sub vcl_fetch { if (beresp.ttl < 120s) { std.log("Adjusting TTL"); set beresp.ttl = 120s; }}
varnish强制缓存cookie
sub vcl_recv {
  if (req.request == "GET" && req.http.cookie) {
     return(lookup);
  }
}

sub vcl_fetch {
  if (beresp.http.Set-Cookie) {
     return(deliver);
 }
}
清楚cache的配置示例:
acl purge {
  "localhost";
  "192.0.2.1"/24;
}

sub vcl_recv {
  if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
      error 405 "Not allowed.";
    }
    return(lookup);
  }
}

sub vcl_hit {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }
}

sub vcl_miss {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }
}

以上仅适合与varnish3.x
################################
本文有笔者参考varnish-cache.org翻译改编
作者:john
转载请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值