varnish配置语言(1)
知识来源为官方文档:
《Varnish用户指南》
《Varnish4.0电子书》
通过对varnish原理的学习,我们知道varnish缓存策略是基于VCL语言实现,处理逻辑是编写在.vcl
配置文件中。
涉及的总要知识点有以下几个:
- vcl语法:运算符、条件语句、子程序、关键字
- 内置Subroutines
- Request and response VCL objects
- action:return(action)
- Functions:内建函数
- 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
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.2 backend-side
vcl_backend_fetch(more)
对后端服务器发送请求时调用 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():当某VCL域运行结束时将控制权返回给Varnish,并指示Varnish如何进行后续的动作;其可以返回的指令包括:lookup、hash、hit、miss、pass、pipe、hit_for_pass、purge等;但某特定域可能仅能返回某些特定的指令,而非前面列出的全部指令;
return(restart):重新运行整个VCL,即重新从vcl_recv开始进行处理;每一次重启都会增加req.restarts变量中的值,而max_restarts参数则用于限定最大重启次数。
ban(expression):清除能被表达式匹配的所有缓存对象
ban_url(regex):Bans所有的其URL可以被此处的regex匹配到的缓存对象;
synth(status,"STRING"):purge操作;
↓
6. 变量
内建变量:
req.*:request,表示由客户端发来的请求报文相关;
req.http.* *可以是http请求报文的任意首部的名称,代表引用http的某个请求首部
req.http.User-Agent, req.http.Referer, ...
req.http.host
req.method 表示客户端的请求方法
req.url 表示客户端请求的url
bereq.*:varnish主机在向后端真实服务器发送http请求报文时的相关变量。
如:可以将真实的客户端地址传递给后端真实web服务器,以便于后端真实服务器记录客户端的真实IP,而不是varnish的IP
bereq.http.* 代表varnish发往后端的真实的web服务器的相关的请求报文中的首部
beresp.*:由后端真实服务器发来的http响应报文中的某些首部信息相关的变量,一般是在vcl_backend_response或vcl_backend_fenth引擎中调用
beresp.http.*
resp.*:由varnish响应给客户端的响应报文相关的变量;
一般用在vcl_deliver引擎中进行调用,因为deliver引擎是用于给客户端构建响应报文,发送响应报文
resp.http.: 可以是响应报文中的任意首部的名称,代表引用某个响应报文的值,可用于设定、添加、修改响应给客户端的响应报文中的响应首部的值
obj.*:对存储在缓存空间中的缓存对象属性的引用变量;只读;
obj.hits: 某个缓存对象的缓存的命中次数
client.,server.,storage.*:可用在所有面向客户端一侧的引擎中,也就是vcl_recv、vcl_pipe、vcl_hash、vcl_pass、vcl_purge、vcl_miss、vcl_hit、vcl_deliver、vcl_synth中:
client.ip 代表客户端的IP地址
server.ip 代表当前varnish的IP地址
client.port 代表客户端的端口
server.port 代表当前varnish的端口
用户自定义变量
可用set,来设定某个用户自定义变量或现有变量的值
可用unset,来取消某个用户自定义变量,或删除现有变量
常用内建变量说明:
-
bereq.*
bereq.http.HEADERS: 表示varnish发往后端真实web服务器的请求报文中的某个首部
bereq.request: 表示varnish发往后端真实web服务器的请求报文的请求方法(4.0版本的varnish改为了bereq.method)
bereq.url:表示varnish发往后端真实web服务器的请求报文的请求的url
bereq.proto:表示varnish发往后端真实web服务器的请求报文的http协议的协议版本
bereq.backend:表示要varnish发送请求到后端真实web服务器时,后端服务器不止一台时,所调用的后端主机 -
beresp.*
beresp.http.HEADERS:表示后端真实web服务器发给varnish的http响应报文的某个首部的信息
beresp.proto:表示后端真实web服务器发给varnish的http响应报文的http协议版本
beresp.status:表示后端真实web服务器发给varnish的http响应报文的响应状态码
beresp.backend.name:表示后端真实web服务器发给varnish的http响应报文的后端主机的名称
beresp.ttl:后端服务器响应中的内容的余下的生存时长 -
obj.*
obj.hit 此对象在缓存中命中的次数
obj.ttl 此对象的ttl值,也就是其缓存时长 -
server.*
server.ip 当前varnish的IP
server.hostname 当前varnish的主机名 -
req.*
req.http.HEADERS: 表示客户端发送给varnish的请求报文中的某个首部
req.request: 表示客户端发送给varnish的请求报文的请求方法(4.0版本的varnish改为了req.method)
req.url:表示客户端发送给varnish的请求报文的请求的url
req.proto:表示客户端发送给varnish的请求报文的http协议的协议版本 -
resp.*
resp.http.HEADERS:表示varnish发送给客户端的响应报文的某个首部的信息
resp.proto:表示varnish发送给客户端的http响应报文的http协议版本
resp.status:表示varnish发送给客户端的http响应报文的响应状态码 -
自定义变量:可用set 变量名= 值 来设定变量。例:
set resp.http.X-Cache = "HIT"
表示设定响应给客户端的响应报文中设定X-Cache首部的值为HIT
set resp.http.IS-Cache = "YES"+" "server.ip
表示设定响应给客户端的响应报文中的IS-Cache首部的值为"YES
varnish服务器IP",多个元素之间要用+加号连接,如果要输出空格,需要用""引号引起来 -
取消某变量:用unset 变量名。例:
unset req.http.cookie
表示取消客户端请求报文中http的cookie首部信息
unset beresp.http.Set-cookie
表示取消后端服务器发送到varnish上的响应报文http首部中的Set-cookie首部
同时注意变量是受状态限制的,下图为可用表:
[sleepy↓]