安装
系统:CentOS7
Varnish版本:4.0
后端web服务器:192.168.253.158
Varnish代理服务器:192.168.253.128
192.168.253.128主机上
#wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo #安装epel源,如果已经有了就不需要执行这个命令 (这条命令对应的是CentOS7系统)
yum install varnish -y
Varnish是一个缓存服务器,也是个代理服务器。如果没有后端真实服务器存在提供服务,它缓存什么?所以需要先设置个后端web服务器。然后让Varnish去代理后端服务器。
192.168.253.158上设置后端web服务器
systemctl stop firewalld
setenforce 0
yum install nginx -y
nginx
echo "192.168.253.158"> /usr/share/nginx/html/index.html
192.168.253.128上修改配置文件
[root@localhost etc]# grep -vE "#|^$" /etc/varnish/default.vcl
vcl 4.0;
backend default {
.host = "192.168.253.158"; ## 代理后端的WEB服务器
.port = "80";
}
sub vcl_recv {
}
sub vcl_backend_response {
}
sub vcl_deliver {
}
启动Varnish
systemctl start varnish
进入Varnish的命令行接口
varnishadm -S /etc/varnish/secret # /etc/varnish/secret是认证文件
可以看到子进程正在运行
配置文件目录结构
[root@localhost etc]# tree /etc/varnish/
/etc/varnish/
├── default.vcl ##默认的Varnish配置文件
├── secret ##认证文件
└── varnish.params ##Varnish运行参数配置
varnish.params配置文件
这个文件设置运行varnish时的参数
# Varnish environment configuration description. This was derived from
# the old style sysconfig/defaults settings
# Set this to 1 to make systemd reload try to switch VCL without restart.
RELOAD_VCL=1
# Main configuration file. You probably want to change it.
VARNISH_VCL_CONF=/etc/varnish/default.vcl #默认的vcl配置文件
# Default address and port to bind to. Blank address means all IPv4
# and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted
# quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=192.168.1.5
VARNISH_LISTEN_PORT=6081 #varnish监听的端口
# Admin interface listen address and port varnish管理接口监听的地址
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
# Shared secret file for admin interface #认证文件路径
VARNISH_SECRET_FILE=/etc/varnish/secret
# Backend storage specification, see Storage Types in the varnishd(5)
# man page for details. #指定缓存 存放的位置
VARNISH_STORAGE="malloc,256M"
# malloc[,size] 内存存储,[,size]用于定义空间大小;重启后所有缓存项失效;
# file[,path[,size[,granularity]]] 磁盘文件存储,黑盒;重启后所有缓存项失效;
# persistent,path,size 文件存储,黑盒;重启后所有缓存项有效;实验;
# User and group for the varnishd worker processes 所属的属主和属组
VARNISH_USER=varnish
VARNISH_GROUP=varnish
# Other options, see the man page varnishd(1) #一些额外参数的选项
#DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
VCL
简介
Varnish Configuration Language (VCL)是一种特定于域的语言,用于描述Varnish Cache的请求处理和文档缓存策略。加载新配置时,由Manager进程创建的VCC进程将VCL代码转换为C.此C代码通常由gcc共享对象编译。然后将共享对象加载到child进程中。
vcl状态引擎
在VCL状态引擎中,状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并指示varnish进入下一个状态。
varnish开始处理一个请求时,首先需要分析HTTP请求本身,比如从首部获取请求方法、验正其是否为一个合法的HTT请求等。当这些基本分析结束后就需要做出第一个决策,即varnish是否从缓存中查找请求的资源。这个决定的实现则需要由VCL来完成,简单来说,要由vcl_recv方法来完成。如果管理员没有自定义vcl_recv函数,varnish将会执行默认的vcl_recv函数。然而,即便管理员自定义了vcl_recv,但如果没有为自定义的vcl_recv函数指定其终止操作(terminating),其仍将执行默认的vcl_recv函数。事实上,varnish官方强烈建议让varnish执行默认的vcl_recv以便处理自定义vcl_recv函数中的可能出现的漏洞。
常用的有几个状态引擎
vcl_recv
vcl_recv是在Varnish完成对请求报文的解码为基本数据结构后第一个要执行的子例程,它通常有四个主要用途:
(1)修改客户端数据以减少缓存对象差异性;比如删除URL中的www.等字符;
(2)基于客户端数据选用缓存策略;比如仅缓存特定的URL请求、不缓存POST请求等;
(3)为某web应用程序执行URL重写规则;
(4)挑选合适的后端Web服务器;
vcl_backend_response
vcl_backend_response在读取了后端服务器响应报文后执行
vcl_deliver
vcl_deliver,向客户端发送响应之前执行
vcl_init
在处理任何请求之前要执行的vcl代码:主要用于初始化VMODs;
vcl_fini
所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;
基本语法规则
- VCL 文件以 vcl 4.0 ; 开头
- //, # 和 /* foo */ 表示注释
- 函数用sub关键字声明,例如 sub vcl { … } ;
- 不支持循环,有内置变量
- 需要用return () 进行下一个动作。例子:return(action)
- 域专用
- include “foo.vcl”; 包含一个VCL文件
- import foo; 加载Varnish模块(VMOD)
VCL内置函数,关键字和操作符
函数
- regsub(str, regex, sub) :用于基于正则表达式搜索指定的字符串并将其替换(替换一次)为指定的字符串
- regsuball(str, regex, sub) :用于基于正则表达式搜索指定的字符串并将其替换(全部替换)为指定的字符串
- ban(boolean expression)
- hash_data(input):对input进行hash
- synthetic(str)
关键词
- call subroutine
- return(action)
- new
- set
- unset
操作符:
- ==, !=, ~, >, >=, <, <=
- 逻辑操作符:&&, ||, !
- 变量赋值:=
VCL内置的公用变量
公用变量名称 | 含义 |
---|---|
req.backend | 指定对应后端主机 |
server.ip | 表示服务器IP |
client.ip | 表示客户端IP |
req.request | 指定请求的类型,例如GET、HEAD和POST等 |
req.url | 指定请求的地址 |
req.proto | 表示客户端发起请求的HTTP协议版本 |
req.http.header | 表示对应请求中的HTTP头部信息 |
req.restarts | 表示请求重启的次数,默认最大值为4 |
Varnish 在向后端主机请求时,可以使用的公用变量
公用变量名称 | 含义 |
---|---|
beresp.request | 指定请求的类型,例如GET或HEAD等 |
beresp.url | 指定请求的地址 |
beresp.proto | 表示客户端发起请求中的HTTP协议版本 |
beresp.http.header | 表示对应请求中的HTTP头部信息 |
beresp.ttl | 表示缓存的生存周期,也就是cache保留多长时间单位是秒 |
从cache或后端主机获取内容后,可以使用的公用变量
公用变量名称 | 含义 |
---|---|
obj.status | 表示返回内容的请求状态码,例如200、302、504等 |
obj.cacheable | 表示返回的内容是否可以缓存,也就是说,如果HTTP返回的是200、203、300、301、302、404或410等,并且有非0的生存期,则可以缓存 |
obj.valid | 表示是否是有效的HTTP应答 |
obj.response | 表示返回内容的请求状态信息 |
obj.proto | 表示返回内容的HTTP协议版本 |
obj.ttl | 表示返回内容的生存周期,也就是缓存时间,单位是秒 |
obj.lastuse | 表示返回上一次请求到现在的间隔时间,单位是秒 |
对客户端应答时,可以使用的公用变量
公用变量名称 | 含义 |
---|---|
resp.status | 表示返回客户端的HTTP状态代码 |
resp.proto | 表示返回客户端的HTTP协议版本 |
resp.http.header | 表示返回客户端的HTTP头部信息 |
resp.response | 表示返回客户端的HTTP状态信息 |
例子
举例1 :如果请求命中缓存了,则在响应报文首部X-Cache添加HIT via + 服务端ip,如果没有命中则添加MISS via + 服务端ip。因为我们添加的报文是在varnish返回客户端这个过程。所以最好在vcl_deliver这个函数里面添加。obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次数;
[root@localhost etc]# grep -Ev "#|^$" /etc/varnish/default.vcl
vcl 4.0;
backend default {
.host = "192.168.253.158";
.port = "80";
}
sub vcl_recv {
}
sub vcl_backend_response {
}
sub vcl_deliver {
set resp.http.X-Cache = "HIT via " + server.ip;
}
else {
set resp.http.X-Cache = "MISS via " + server.ip;
}
}
动态修改配置文件
varnishadm -S /etc/varnish/secret #进入Varnish的命令行管理
#varnish的命令行管理接口内
vcl.load X-cache /etc/varnish/default.vcl #装载 /etc/varnish/default.vcl配置文件,命名为X-cache
vcl.use X-cache #使用X-cache这个配置文件
可以看到X-cache这个配置文件已经激活了
可以访问一次192.168.253.128的6081端口
这时候我们看到缓存没有命中。因为是第一次访问,我们再次刷新就可以看到命中了
举例2:强制对某类资源的请求不检查缓存
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") { #(?i)不区分大小写
return(pass);
}
}
举例3:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长; 定义在vcl_backend_response中;
if (beresp.http.cache-control !~ "s-maxage") {
if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {
unset beresp.http.Set-Cookie;
set beresp.ttl = 3600s;
}
}
举例4:定义在vcl_recv中;
if (req.restarts == 0) {
if (req.http.X-Fowarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
修建缓存对象
清理缓存有2种方法purge和ban
purge
purge用于清理缓存中的某特定对象,因此,在有着明确要修剪的缓存对象时可以使用此种方式。
vcl示例
vcl 4.0;
backend default {
.host = "192.168.253.158";
.port = "80";
}
acl purgers { ##设置访问控制列表
"127.0.0.0"/8;
"192.168.253.0"/24;
}
sub vcl_purge {
return (synth(200,"Purged")); #合成一个200响应码显示已经删除了。
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) { ##如果客户端不再访问控制列表里面 则返回405错误
return(synth(405,"Purging not allowed for " + client.ip));
}
return(purge);
}
}
sub vcl_backend_response {
}
sub vcl_deliver {
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via " + server.ip;
}
else {
set resp.http.X-Cache = "MISS via " + server.ip;
}
}
重新装载配置文件
[root@localhost ~]# varnishadm -S /etc/varnish/secret
200
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,3.10.0-693.el7.x86_64,x86_64,-smalloc,-smalloc,-hcritbit
varnish-4.0.5 revision 07eff4c29
Type 'help' for command list.
Type 'quit' to close CLI session.
vcl.load PURGE_ACL /etc/varnish/default.vcl ##装载配置文件
200
VCL compiled.
vcl.use PURGE_ACL ## 使用配置文件
200
VCL 'PURGE_ACL' now active
可以看到一开始是命中缓存的,当使用PURGE请求的时候就吧缓存删除了,于是下一次访问时候,显示MISS。说明通过PURGE方法我们删除了缓存对象
ban
ban()是一种从已缓存对象中过滤(filter)出某此特定的对象并将其移除的缓存内容刷新机制,不过,它并不阻止新的内容进入缓存或响应于请求。在Varnish中,ban的实现是指将一个ban添加至ban列表(ban-list)中,这可以通过命令行接口或VCL实现,它们的使用语法是相同的。ban本身就是一个或多个VCL风格的语句,它会在Varnish从缓存哈希(cache hash)中查找某缓存对象时对搜寻的对象进行比较测试。
定义好的所有ban语句会生成一个ban列表(ban-list),新添加的ban语句会被放置在列表的首部。缓存中的所有对象在响应给客户端之前都会被ban列表检查至少一次,检查完成后将会为每个缓存创建一个指向与其匹配的ban语句的指针。Varnish在从缓存中获取对象时,总是会检查此缓存对象的指针是否指向了ban列表的首部。如果没有指向ban列表的首部,其将对使用所有的新添加的ban语句对此缓存对象进行测试,如果没有任何ban语句能够匹配,则更新ban列表。
对ban这种实现方式持反对意见有有之,持赞成意见者亦有之。反对意见主要有两种,一是ban不会释放内存,缓存对象仅在有客户端访问时被测试一次;二是如果缓存对象曾经被访问到,但却很少被再次访问时ban列表将会变得非常大。赞成的意见则主要集中在ban可以让Varnish在恒定的时间内完成向ban列表添加ban的操作,例如在有着数百万个缓存对象的场景中,添加一个ban也只需要在恒定的时间内即可完成。
使用方法有2种
(1)在命令行接口使用
格式:
ban <field> <operator> <arg>
示例
现在缓存是命中的。
[root@localhost varnish]# varnishadm -S /etc/varnish/secret
200
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,3.10.0-693.el7.x86_64,x86_64,-smalloc,-smalloc,-hcritbit
varnish-4.0.5 revision 07eff4c29
Type 'help' for command list.
Type 'quit' to close CLI session.
ban req.url ~ /.*html ##ban掉匹配到/.*html的url
200
然后我们再次访问
(2)在配置文件中定义,使用ban()函数;
[root@localhost ~]# grep -Ev "#|^$" /etc/varnish/default.vcl
vcl 4.0;
backend default {
.host = "192.168.253.158";
.port = "80";
}
acl purgers {
"127.0.0.0"/8;
}
sub vcl_recv {
if (req.method == "BAN") {
return(synth(405,"Purging not allowed for " + client.ip));
}
else{
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200,"Ban added"));
}
}
}
sub vcl_backend_response {
}
sub vcl_deliver {
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via " + server.ip;
}
else {
set resp.http.X-Cache = "MISS via " + server.ip;
}
}
测试之前我们访问了一次显示缓存命中了,然后使用BAN请求。显示BAN 添加成功
然后我们再访问一次,显示缓存没有命中“MISS”
我们这个配置文件的访问控制列表仅允许127.0.0.1执行ban操作。当我们使用192.168.253.128这个ip访问时,会显示不允许执行此操作