varnish配置语言


通过对varnish原理的学习,我们知道varnish缓存策略是基于VCL语言实现,处理逻辑是编写在.vcl配置文件中
涉及的总要知识点有以下几个

  1. vcl语法:运算符、条件语句、子程序、关键字
  2. 内置Subroutines
  3. Request and response VCL objects
  4. action:return(action)
  5. Functions:内建函数
  6. Variables:变量

1. vcl语法

varnish 4.0版本开始,vcl拥有自己的默认规则,它不可移除,总是追加在自定义的规则之后。

  • vcl配置文件以 vcl 4.0 开头;
  • C语言注释风格://or#or/* foo */;
  • 子函数使用sub关键字声明, 例如sub vcl_recv { ...};
  • 无循环, state-limited variables(受限于引擎的内建变量);
  • 使用return(action)中断引擎状态,指向下一步处理,action为关键字 ,例如: return(pass);
  • 可动态装载;

VCL4相比VCL3语法的改变点

  • 要在配置文件中指定版本:即在第一行写上 vcl 4.0;
  • vcl_fetch函数被vcl_backend_response代替,且req.*不再适用vcl_backend_response;
  • 后端源服务器组director成为varnish模块,需import directors后再在vcl_init子例程中定义;
  • vcl_error变更为vcl_backend_error,必须使用beresp.,而不是obj.
  • req.request变更为req.method,obj为只读对象了。
  • 自定义的子例程(即一个sub)不能以vcl_开头,调用使用call sub_name;
  • error()函数被synth()替代;
  • return(lookup)被return(hash)替代;
  • 使用beresp.uncacheable创建hit_for_pss对象;
  • 变量req.backend.healty被std.healthy(req.backend)替代;
  • 变量req.backend被req.backend_hint替代;
  • 关键字remove被unset替代;
  • 关键字"purge;"命令,已被去除。在vcl_recv使用return(purge)。
  • vcl_synth采用resp.,而非原来的obj.

1.1 主体语法

sub subroutine {
...
}
if CONDITION {
...
} else {
...
}
return()  # Functions
hash_data() # Functions

1.2 操作符

= 赋值
== 等于
~ 匹配,可以与正则表达式或ACL一起使用。同时注意匹配的规则如果是字符串,则需要 " " 引起。
! 逻辑非
&& 逻辑与
|| 逻辑或

1.3 Subroutines

子例程
子例程用于对代码进行分组以提高可读性或可重用性,例:

sub pipe_if_local {
    if (client.ip ~ localnetwork) {
        return (pipe);
    }
}

VCL中的子例程不带参数,也不返回值。内置子例程的名称均以vcl_开头。
要调用子例程,请使用call关键字,后跟子例程的名称:

sub vcl_recv {
    call pipe_if_local;
}

Varnish具有许多内置的子例程,这些子例程在每次事务流经Varnish时都会被调用。这些内置的子例程都名为vcl_*。您自己的子例程不能以vcl_开头其名称。

Return
当执行return(action)语句时,正在进行的vcl_ *子例程执行结束。
该操作指定执行的方式。上下文定义了可用的动作。

1.4 关键字

call subroutine, return(action),new,set,unset

2. 内置的Subroutines

内置函数4.0

Varnish 处理 client 的请求和后端服务器的响应时,会调用多个内置的 subroutines 进行处理。通过 CLI 执行 vcl.load 和 vcl.discard 时,也会调用内置的 subroutines。

下面对前端(client-side)和后端(backend-side)的处理分别进行介绍:

2.1 client-side

vcl_recv

在请求开始时调用,在接收并解析完整的请求之后调用,在重新启动之后调用,或者作为ESI include的结果调用。
它的目的是决定是否为请求服务,可能会修改它,并决定如何进一步处理它。可以将后端提示设置为后端处理端默认设置。

vcl_recv 子例程可使用 return() 结合下面的其中一个关键字进行终止:

hash
    请求的对象被认为是一个可能被缓存的对象,将继续对其进行处理。将控制权转交给 vcl_hash 子例程。

pass
    转换至 pass 模式。控制权最终交给 vcl_pass 子例程。

pipe
    转换至 pipe 模式。控制权最终交给 vcl_pipe 子例程。

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason

purge
    清除请求的对象,以及它的变量(variants)。控制权先交给 vcl_hash,最终交给 vcl_purge

vcl_pipe

进入 pipe 模式时,vcl_pipe 子例程将被调用。在这个模式中,请求将被传递给后端服务器,这时 Varnish 会降级成为一个 TCP 代理,只充当一个数据流的通道,不会对数据进行任何修改,当 client 或 server 端决定关闭连接时,该模式结束。在调用 vcl_pipe 之后,对于一个处于 pipe 模式的连接,其他任何的 VCL 子例程都不会被调用。

vcl_pipe 子例程可使用 return() 结合下面的其中一个关键字进行终止:

pipe
    继续以 pipe mode 运行

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason

vcl_pass

在进入 pass 模式时,vcl_pass 将被调用,请求被转发给后端服务器,后端服务器的响应被转发给 client,但是响应不会被缓存。来自该 client 连接的后续请求,将被正常处理。

vcl_pass 子例程可使用 return() 结合下面的其中一个关键字进行终止:

fetch
    继续以 pass mode 运行 - 发起一个对后端服务器的请求

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,Varnish 发出一个错误:guru meditation error.

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason

vcl_hit

当缓存查找成功,vcl_hit 将被调用。缓存对象可能会过期,其 ttl 可能为 0 或者负数,with only grace or keep time left.

vcl_hit 子例程可使用 return() 结合下面的其中一个关键字进行终止:

deliver
    发送该对象。如果该对象过期,将触发一个 fetch 调用,更新该对象。

fetch
    尽管缓存命中,但是会同步地从后端服务器更新缓存对象。控制权最终转交给 vcl_miss。

pass
    转换至 pass 模式。控制权最终交给 vcl_pass 子例程。

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,Varnish 发出一个错误:guru meditation error.

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason    

vcl_miss

当缓存查找失败,或者当 vcl_hit 返回一个 fetch 时,调用 vcl_miss。
vcl_miss 用于决定是否尝试从后端服务器获取文件。

vcl_miss 子例程可使用 return() 结合下面的其中一个关键字进行终止:

fetch
    从后端服务器获取请求的对象。控制权最终转交给 vcl_backend_fetch。

pass
    转换至 pass 模式。控制权最终交给 vcl_pass 子例程。

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,Varnish 发出一个错误:guru meditation error.

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason

vcl_hash

当 vcl_recv 为请求创建了一个 hash 值时被调用。使用该值作为 key 进行缓存查找。

vcl_hash 子例程只能以 return(lookup) 终止:

lookup
    在缓存中查找请求的对象。如果从 vcl_recv 返回 return(purge),控制权转交给 vcl_purge。
    否则,如果缓存查找的结果是 hit,控制权转交给 vcl_hit;如果缓存查找的结果是 miss,控制权转交给 vcl_miss;
    如果缓存查找的结果是 hit on a hit-for-pass 对象 (object with obj.uncacheable == true),控制权转交给 vcl_pass。

vcl_purge

执行 purge 之后,vcl_purge 被调用,缓存对象被清除(失效),其所有变量(variants)将被回避。

vcl_purge 子例程可使用 return() 结合下面的其中一个关键字进行终止:

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,Varnish 发出一个错误:guru meditation error.

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason    

vcl_deliver

发送对象给客户端前调用,除了将一个 vcl_synth 结果发送给客户端时不会调用。

vcl_deliver 子例程可使用 return() 结合下面的其中一个关键字进行终止:

deliver
    发送对象给 client

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,Varnish 发出一个错误:guru meditation error.

synth(status code, reason)
    转移到 vcl_synth 子例程,synth() 的参数值被预置为 resp.status 和 resp.reason

vcl_synth

调用 vcl_synth 可以发送一个 synthetic 对象给客户端。synthetic 对象由 VCL 生成,不是从后端获取的。可使用 synthetic() 函数构造 synthetic 对象。

vcl_synth 定义了一个对象,该对象不会被缓存,与其相反,vcl_backend_error 所定义的对象可能最终被缓存。

vcl_synth 子例程可使用 return() 结合下面的其中一个关键字进行终止:

deliver
    直接将 vcl_synth 定义的对象发送给客户端,不调用 vcl_deliver

restart
    重启该 transaction。增加 restart 计数器的计数。如果计数超过了 max_restarts,
    Varnish 发出一个错误:guru meditation error.

2. backend-side

vcl_backend_fetch

对后端服务器发送请求时调用 vcl_backend_fetch。在这个子例程中,我们一般会修改请求,然后才发送给后端服务器。

vcl_backend_fetch 子例程可使用 return() 结合下面的其中一个关键字进行终止:

fetch
    从后端服务器获取对象

abandon
    放弃对后端发起请求。除非后端请求是一个 background fetch,否则控制权将被转交给 client-side 的 vcl_synth,
    其 resp.status 被设置为 503。

vcl_backend_response

当成功从后端服务器获取到 response headers 时,调用 vcl_backend_response。

vcl_backend_response 子例程可使用 return() 结合下面的其中一个关键字进行终止:

deliver
    对于一个 304 响应,创建一个更新的缓存对象。否则,从后端获取对象的 body,然后发起 delevery 返回给客户端。
    很可能是并行的(streaming)

abandon
    放弃对后端发起请求。除非后端请求是一个 background fetch,否则控制权将被转交给 client-side 的 vcl_synth,
    其 resp.status 被设置为 503。
        
retry
    重试发起 backend transaction。增加重试计数,如果重试次数超过 max_retries,控制权转交给 vcl_backend_error

vcl_backend_error

当尝试从后端获取对象失败,或则重试次数超过 max_retries 时,vcl_backend_error 将被调用。

VCL 生成一个 synthetic 对象,可使用 synthetic() 函数构造 synthetic 对象的 body。

vcl_backend_error 子例程可使用 return() 结合下面的其中一个关键字进行终止:

deliver
    发送 vcl_backend_error 定义的对象,可能的话,缓存该对象。就如同该对象是从后端获取的一般。这也被称为 "backend synth"。

retry
    重试发起 backend transaction。增加重试计数,如果重试次数超过 max_retries,调用 client-side 的 vcl_synth,
    其 resp.status 被设置为 503。

2.3 vcl.load / vcl.discard

vcl_init

当加载 VCL 之后,vcl_init 被调用。一般用于初始化 VMODs。

vcl_init 子例程可使用 return() 结合下面的其中一个关键字进行终止:

ok
    正常返回,VCL 继续加载

fail
    停止加载这个 VCL  

vcl_fini

当一个 VCL 被废弃,当该 VCL 处理完所有请求,调用 vcl_fini。一般用于清除 VMODs。

vcl_fini 子例程可使用 return() 结合下面的其中一个关键字进行终止:

ok
    正常返回,VCL 将被废弃。

3. Request and response VCL objects

VCL中有些需要你注意的重要对象。这些对象可以在VCL被使用和操作

---req
请求对象。当vanish接收到请求后,req对象被创建和生成。你可以在vcl_recv中使用req对象做很多事。

---bereq
The backend request object. Varnish contructs this before sending it to the backend. It is based on the req object.
后端请求对象。varnish在发送请求到后端之前构建这个对象。它基于req对象。

---beresp
后端响应对象。它包含在从后端响应对象的头里。如果你想修改后端server返回的响应信息,你可以在vcl_backend_response中修改beresp对象。

---resp
传递给客户端响应之前的response对象。通常在vcl_deliver中修改。

---obj
The object as it is stored in cache. Read only.
存储在缓存中的对象。 只读。

4. action:return(action)

actions 是在终止一个内置子例程时,配合 return() 使用的,如 return(pass),最常用的 actions 是这些:

---pass
当你在子程序中return(pass)请求和随后的响应将被传递到后端server和从后端server回传回来。响应将不会被缓存。pass可以从vcl_recv中返回。

---hash
在*vcl_recv*中return(hash),通知varnish从cache查找请求内容,除非这个请求不被标示,那么请求应当被pass。

---pipe .. XXX:What is pipe? benc
如果从 vcl_recv 返回 pipe,将会进入 pipe 模式,Varnish 将前端与客户端的连接,以及与后端服务器的连接合并成一个数据流的通道,Varnish 不对数据做任何修改,只是将数据在两端发送,所以你的日志是不完整的。
pipe也可以在*vcl_recv*中返回,return(pipe)。

---deliver
传递对象给客户端。通常在vcl_backend_response中return。

---restart
Restart processing of the request. You can restart the processing of the whole transaction. Changes to the req object are retained.
重新对请求进行处理。你可以在整个请求处理的阶段重启。更改过的req对象将被保留。

---retry
Retry the request against the backend. This can be returned from vcl_backend_response or vcl_backend_error if you don't like the response that the backend delivered .
重启指向后端的请求。如果你不想从后端获得响应,你可以在vcl_backend_response 或者vcl_backend_error 中return。

5. 内建函数

hash_data():指明哈希计算的数据;减少差异,以提升命中率;
regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite
regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;
return():
ban(expression)
ban_url(regex):Bans所有的其URL可以被此处的regex匹配到的缓存对象;
synth(status,"STRING"):purge操作;

下图为指定函数只能用于特定子函数中:

内建函数

6. 变量

内建变量

req.*:request,表示由客户端发来的请求报文相关;
req.http.*
req.http.User-Agent, req.http.Referer, ...
bereq.*:由varnish发往BE主机的httpd请求相关;
bereq.http.*
beresp.*:由BE主机响应给varnish的响应报文相关;
beresp.http.*
resp.*:由varnish响应给client相关;
obj.*:存储在缓存空间中的缓存对象的属性;只读;

常用变量

bereq.*, req.*:
bereq.http.HEADERS
bereq.request:请求方法;
bereq.url:请求的url;
bereq.proto:请求的协议版本;
bereq.backend:指明要调用的后端主机;
req.url:请求的url
req.http.Cookie:客户端的请求报文中Cookie首部的值;
req.http.User-Agent:浏览器类型

beresp.*, resp.*:
beresp.http.HEADERS
beresp.status:响应的状态码;
reresp.proto:协议版本;
beresp.backend.name:BE主机的主机名;
beresp.ttl:BE主机响应的内容的余下的可缓存时长;

obj.*
obj.hits:此对象从缓存中命中的次数;
obj.ttl:对象的ttl值

server.*
server.ip
server.hostname
client.*
client.ip

同时注意变量是受状态限制的,下图为可用表:


 
[sleepy↓]





猜你喜欢

转载自www.cnblogs.com/sunhongleibibi/p/11720212.html