Varnish是一款高性能的缓存加速器,具有稳定,且效率更高,资源占用更少等特点。
缓存存储的格式:
key-value:
key:访问路径,URL, hash
value:web content
命中率:hit/(hit+miss)
文档命中率:从文档个数进行衡量;
字节命中率:从内容大小进行衡量;
注意:
缓存对象:生命周期;定期清理;
缓存空间耗尽:LRU(最近最少使用算法)
可缓存对象,不可缓存对象(用户私有数据)
缓存处理的步骤:
接收请求 --> 解析请求 (提取请求的URL及各种首部)--> 查询缓存 --> 新鲜度检测 --> 创建响应报文 -->发送响应 --> 记录日志
新鲜度检测机制:
1、 过期日期:
Expires;例:Expires:Thu, 04 Jun 2015 23:38:18 GMT,是在这个时间以前都有效
Cache-Control:max-age;例:Cache-Control:max-age=600,缓存有效时间为600s(秒)
2、有效性再验证:revalidate,就是查到缓存以后,去向服务器端发送一个条件式请求,
如果原始内容未改变,则仅响应首部(不附带body部分),响应码304 (Not Modified)
如果原始内容发生改变,则正常响应,响应码200;
如果原始内容消失,则响应404,此时缓存中的cacheobject也应该被删除;
3、条件式请求首部:
If-Modified-Since:基于请求内容的时间戳做验正;就是自从什么时间开始发生改变
If-Unmodified-Since:自从什么时间开始没有发生改变
If-Match:是否匹配
If-None-Match:是否你匹配
Etag:fdsfad9345,扩展标签,是校验码
浏览器发送一个请求,先经过缓存,如果缓存服务器没有,就会找服务器端来响应,如果这个报文可以缓存,会缓存到缓存服务器,然后响应给浏览器;如果浏览器在发送一个相同的请求,如果缓存没有过期,就会从缓存服务器直接响应的
常见的缓存服务开源解决方案:
varnish, squid
要想操作varnish,需要使用varnish的操作语言vcl,vcl的配置文件首先要被c编译器编译成二进制格式,然后才被varnish加载使用
vcl: Varnish Configuration Language,缓存策略配置接口;基于“域”的简单编程语言
varnish分为管理进程和子进程
管理进程:编译VCL并应用新配置;监控vanish;初始化varnish;CLI接口;
子进程(Child/cache)包括:
Acceptor:接收新的连接请求;
workerthreads:处理用户请求;
Expiry:清理缓存中的过期对象;
Log/stats:日志相关的
日志:Shared Memory Log,共享内存日志大小默认一般为90MB,分为两部分,前一部分为计数器,后一部分请求相关的数据;
varnish如何存储缓存对象:
file:单个文件;不支持持久机制;
malloc:内存;
persistent:基于文件的持久存储;在生产中是不可用的
varnish的安装包在epel源中有提供,提供的是4.0版本的varnish,可以直接安装,
varnish的配置文件为/etc/varnish/default.vcl,
varnish的命令行参数的配置文件/etc/varnish/varnish.params
varnish的服务文件在/usr/lib/systemd/system/varnish.service
配置varnish的三种配置应用方式:
1、varnishd应用程序的命令行参数;(定义varnish主程序的工作特性)
监听的socket, 使用的存储类型等等;额外的配置参数;
-pparam=value :设置额外的参数
-rparam,param,... : 设定只读参数列表;
-fconfig:指定配置文件的,指到哪去读vcl配置文件的
-aaddress[:port][,......]:指定服务监听的地址和端口的,可以指定多个,默认监听的端口是6081(提供服务的端口)和6082(管理接口)
-s[name=]type[,options]:指定缓存使用哪一种存储机制的
-Taddress[:port]:指定管理的地址和接口
/etc/varnish/varnish.params:命令行参数的配置文件(CentOS7中常用)
2、-p选项指明的参数:(定义varnish各子进程或线程的工作特性)
运行时参数:也可在程序运行中,通过其CLI进行配置;
3、vcl:配置缓存系统的缓存机制;(指明线程中的缓存功能的工作机制)
通过vcl配置文件进行配置;
先编译,后应用;依赖于c编译器;
下面以实例和和概念相结合的方式,讲述下varnish的相关知识和简单应用
172.16.249.195为varnish所在的主机,
/etc/varnish/varnish.params文件中定义了varnish主程序的特性,即varnish启动时的参数
VARNISH_VCL_CONF=/etc/varnish/default.vcl :定义了从哪读取vcl的配置
VARNISH_LISTEN_PORT=6081:服务监听的端口,没指明地址代表所有地址
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:定义了管理的地址
VARNISH_ADMIN_LISTEN_PORT=6082 :定义了管理的接口
VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G":缓存的存储机制的定义
VARNISH_TTL=120:varnish联系后端服务器的超时时间
... ...
修改缓存使用的机制,改为使用内存:VARNISH_STORAGE="malloc,128M"
提供一台主机启动httpd服务(172.16.249.115),提供测试页
for i in{1..10};do echo "Page $i on Web1" > /var/www/html/test$i.html;done
/etc/varnish/default.vcl文件中的是vcl的配置,
修改配置:
这一段是配置后端服务器地址和端口的
这样就可以启动varnish了(systemctl start varnish.service)
可以看到启动成功了,访问测试一下,记得端口是6081,
varnish的命令行工具:
1、varnishadm
使用varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082,进入varnish的管理接口
-S:指明密钥文件所在位置,-T:指明端口和IP地址
进入后,使用help可以查看可以使用的命令
ping:探测后端服务器是否在线
status:显示子进程的工作状态
vcl.list:显示所有可以使用的vcl文件,
vcl.load <configname><filename>:编译vcl文件(filename),然后取一个名(configname)
active:指正在使用的vcl配置文件
available:可用的vcl配置文件
vcl.use <configname>:切换使用的vcl文件
可以看到现在使用的就是test这个vcl文件了
vcl.discard <configname>:删除可用的vcl文件的
param.show [-l] [<param>] :显示参数,
param.show:显示所有的参数
-l:显示详细的信息
param.show<param>:只显示一个参数的信息
param.set <param> <value>:设置参数的
storage.list:显示正在使用的缓存列表
vcl.show boot:可以显示boot文件编译以前的样子
backend.list:显示后端服务器列表的
ban <field> <operator><arg> [&& <field> <oper> <arg>]...:清理缓存中的缓存对象
ban.list:定义的ban规则的列表
这可以动态装载vcl配置文件的,后续的很多操作都是在这个接口里操作的
2、Log:
varnishlog :显示日志信息的,需要访问一下,才会出内容的
varnishncsa:这个也是显示日志信息的的,需要访问一下,才会出内容的
这两个日志信息的显示格式不同,这两个命令行接口的使用,如有需要可以去网上搜索下
3、Top:排序后的信息
varnishtop:
4、Statistics:统计信息的
varnishstat:显示缓存相关的信息
-l:显示所有可以显示的字段
这些字段中,常用的有:
MAIN.cache_hit:缓存命中的次数
MAIN.sess_conn:统计varnish已经处理过多少请求了
MAIN.sess_drop:统计varnish已经丢弃过多少请求
... ...
-f NAME:只显示指定字段的信息
vcl:
stateengine:各引擎之间存一定程度上的相关性;前一个engine如果可以有多种下游engine,则上游engine需要用return指明要转移的下游engine;
vcl_recv
vcl_hash
vcl_hit
vcl_miss
vcl_fetch
vcl_deliver
vcl_pipe
vcl_pass
vcl_error
vcl编程语言语法:
(1)//, #, /* */ 用于注释;会被编译器忽略;
(2)sub $name: 用于定义子例程;
subvcl_recv { }
(3)不支持循环;
(4)有众多内置的变量,变量的可调用位置与state engine有密切相关性;
(5)支持终止语句,return(action);没有返回值;
(6)"域"专用;
(7)操作符:=, ==, ~, !, &&, ||
条件判断语句:
if(CONDTION) {
}else {
}
变量赋值:set name=value
撤销变量的值:unset name
varnish中常用的变量:
req.http.HEADER:调用request报文中http协议的指定的HEADER首部;
req.http.X-Forwarded-For
req.http.Auhtorization
req.http.cookie
req.request:请求方法
client.ip:客户端IP;
vcl(v3)的工作机制流程图:
state engine workflow(v3):vcl的v3版本的引擎工作机制:
vcl_recv--> vcl_hash --> vcl_hit --> vcl_deliver
vcl_recv--> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
vcl_recv--> vcl_pass --> vcl_fetch --> vcl_deliver
vcl_recv--> vcl_pipe
vcl(v4)的工作机制流程图:
可以去这里查看https://www.varnish-software.com/book/4.0/_images/simplified_fsm.svg
state engine(v4)
vcl_recv
vcl_pass
vcl_pipe
vcl_hash
vcl_hit
vcl_miss
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
vcl_purge
vcl_synth
state engine workflow(v4):vcl的v34版本的引擎工作机制跟v3类似,就不再多解释了
下面演示操作vcl,实现一些简单应用:在CentOS7中演示,使用的varnish为4.0的版本
首先备份一份/etc/varnish/default.vcl,复制/etc/varnish/default.vcl到/etc/varnish/test.vcl
修改/etc/varnish/test.vcl配置文件:
在sub vcl_recv {}里面加入下面内容:
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method !="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 (hash);
然后保存,使用varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082进入管理接口
然后使用vcl.load test1 test.vcl 装载刚在我们编写的配置文件,如果配置文件有错,会报错的;然后查看下vcl可用列表,使用vcl.use test1切换到test1上
这定义的是一些默认的信息,没法测试,能加载成功就没问题了
下面修改test.vcl,在sub vcl_deliver {}中加入
if (obj.hits>0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
这是自己定义的一个响应报文首部,如果命中就显示HIT,没命中显示MISS;obj.hits是命中的次数
保存退出,然后在varnishadm接口下输入下面内容:
然后访问测试下:用一台虚拟机使用curl命令测试,-I选项是显示报文首部信息的
可以看到第一次请求是是没有缓存的,第二次就使用缓存了
varnish中的内置变量:
变量种类:
client
server:是varnish本身相关的
req:客户端发的请求
resp:缓存服务器或代理服务器响应的
bereq:是varnish往后端服务器请求的
beresp:后端服务器响应过来的内容
obj:后段服务器响应过来的内容或者从缓存中取得的内容的属性
storage:缓存存储有效性的
bereq
bereq.http.HEADERS:由varnish发往backend server的请求报文的指定首部;
bereq.request:请求方法;
bereq.url:请求的url
bereq.proto:使用的协议版本
bereq.backend:指明要调用的后端主机;
beresp
beresp.proto:使用的协议版本
beresp.status:后端服务器的响应的状态码
beresp.reason:原因短语;
beresp.backend.ip:后端服务器的ip地址
beresp.backend.name:后端服务器的主机名称
beresp.http.HEADER:从backend server响应的报文的首部;
beresp.ttl:后端服务器响应的内容的余下的生存时长;
obj
obj.ttl:对象的ttl值;
obj.hits:此对象从缓存中命中的次数;
server
server.ip:缓存服务器自己的ip地址
server.hostname:缓存服务器自己的主机名
req
rep.http
rep.url
......
resp
resp.http
resp.status
... ...
storage
storage.<name>.free_space:缓存空间的空闲空间大小
storage.<name>.use_space:缓存空间的已用空间大小
storage.<name>.happy:缓存是否还有效
Functions(函数)
ban(expression):清理缓存的
return()
new()
regsub(str,regex,sub):正则表达式替换,把str替换为sub,但只替换第一次出现的
regsuball(str,regex,sub):正则表达式替换,把str替换为sub,替换所有的
详细的varnish的内置变量等可以查看官方文档:
https://www.varnish-cache.org/docs/4.0/reference/vcl.html#varnish-configuration-language
在刚才的test.vcl配置文件中修改,在sub vcl_deliver{}中修改如下:
然后在加载,使用
测试下
可以看到使用成功了
示例:强制对某资源的请求,不检查缓存
修改test.vcl如下,在sub vcl_recv {}里加入:
if (req.url ~ "^/test7.html$") {
return(pass);
}
然后在varnishadm命令行接口中做,vcl.load和vcl.use
然后做测试,首先请求其他资源,可以看到能使用缓存
然后请求test7.html
可以看到没有使用缓存
强制对下面两类资源的请求,不检查缓存;
/admin
/login
修改test.vcl配置文件,修改配置文件的sub vcl_recv {},修改为如下:
if(req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
return(pass);
}
然后在后端的服务器的/var/www/html目录下,创建每一个admin目录,然后提供测试页,然后在varnishadm命令行接口中做,vcl.load和vcl.use,在测试可以看到不缓存。这里就不再演示了,跟上面的类似。
示例:对特定类型的资源取消其私有的cookie标识,并强行设定其可以varnish缓存的时长
修改test.vcl配置文件,在vcl_backend_response{}中,加入下面这些内容:
if (beresp.http.cache-control !~ "s-maxage") {
if(bereq.url ~ "(?i)\.jpg$") {
setberesp.ttl = 3600s;
unsetberesp.http.Set-Cookie;
}
if(bereq.url ~ "(?i)\.css$") {
setberesp.ttl = 600s;
unsetberesp.http.Set-Cookie;
}
}
然后在varnishadm命令行接口中做,vcl.load和vcl.use
然后在后端主机上加载一个图片,在/var/www/html目录下,下载1.jpg和2.jpg的图片
然后在访问测试下,因为首部显示的不全,一般默认缓存一会就结束了,我们在里面定义的是定义的是3600s,这个缓存是缓存在varnish中,所以一个小时内请求这个资源都会使用缓存
等几分钟,然后在访问这个资源,会发现还是使用缓存
这样就做好了,就是不太容易看出效果,
backend server的定义:
backendname {
.attribute = "value";
}
.host:backend主机的IP;
.port:backend主机监听的PORT;
.probe:对backend做健康状态检测;
.probe = {...}
.max_connections:并连接最大数量;
后端主机的健康状态检测方式:
probename {
.attribute = "value";
}
.url:判定BE健康与否要请求的url;
.expected_response:期望响应状态码;默认为200;
示例:做两个后端服务器,然后做健康状态检测,再做下分离,让访问图片资源的调度到一台后端服务器上,访问其他资源的调度到令一台后端主机上
修改test.vcl配置文件,如下:
然后在varnishadm命令行接口中做,vcl.load和vcl.use
然后打开另一个虚拟机(172.16.249.159)设置测试页,for i in {1..10};do echo "Page $i in Web2" >/var/www/html/test$i.html ;done,这个主机里没有图片
在varnishadm命令行接口中,使用backend.list,可以查看到后端服务器的信息和状态
访问测试
可以看到图片资源的是发送给web1主机(172.16.249.115)了,请求的.html资源的是发送给web2主机(172.16.249.159)了
示例:实现负载均衡
修改test.vcl配置文件:
这样负载均衡就定义好了,但是这样不好查看效果,因为有缓存,为了演示效果加入
就是访问test7.html时不让缓存,这样访问时就可以看到负载均衡效果了
然后在varnishadm命令行接口中做,vcl.load和vcl.use
访问测试
可以看懂访问test7.html时是负载均衡,访问其他资源时,是使用的缓存,所以不会变
或者使用这个方式测试,每次使用一个新资源范围,也可以看到负载均衡效果
直接在物理机中测试也行,物理机中的浏览器访问时是不允许缓存的,所以可以看到负载均衡效果,如果你的物理机的浏览器对这些资源是允许缓存的话,就只能用上面的方法定义一个资源,让它不缓存
可以负载均衡
这样负载均衡就做好了
如果有不明白的配置可以到这个连接下去查看varnish的官方配置示例:https://www.varnish-cache.org/trac/wiki/VCLExamples