一 varnish 简要概括
Varnish是一款轻量级的Cache和反向代理软件。
官方网站:https://www.varnish-cache.org/
二 varnish同squid相比
相同点:
都是开源软件
都可做为缓存和发向代理软件使用
varnish的优点:
varnish访问速度快。varnish将数据缓存在内存中,squid将缓存数据放置在磁盘上。
varnish可以使用管理接口,使用正则表达式修剪缓存数据,squid做不到。
varnish支持更多的并发连接。varnish的TCP连接释放速度高于squid,在高并发的情况下支持更多的TCP连接。
varnish的缺点:
varnish的进程一旦崩溃,重启,缓存在内存中的数据将会丢失,来自前段的访问流量涌向后端
varnish在负载较大的情况下,没有squid稳定。
三 varnish设计结构
varnish运行的两类进程:management进程和child/cache进程。
3.1)management进程作用:
编译VCL书写的策略,应用新的配置,初始化varnish,监控child进程,提供管理接口
management进程间隔数秒探测child进程,若timeout时间内没有获得回应,会重启child进程。
management提供的管理接口有三种:命令行接口和telnet远程接口,还有gui图形接口(要收费的)。
3.2)child/cache进程作用:
使用accept线程:接收新的连接请求并响应
使用worker线程:child为每一个会话启用一个worker线程,在高并发场景中会有多个worker线程存在。
使用expiry线程:从缓存中清理过期的内容
使用Log/stats线程:管理日志
使用command line线程:管理接口
使用storage/hashing线程:管理存储
使用backend communication线程:管理后端主机
3.3)日志管理:
varnish的日志是共享内存日志,线程若想写日志记录信息,需维持持有一个锁,然后向共享内存中的日志区域写入数据,然后再释放锁。对应worker线程,使用了日志数据缓存功能,防止日志写入竞争。共享日志大小一般为90M,分为2个部分:前一部分为基数器,后一部分为客户端请求数据。
四 varnish的工作流程:
图中椭圆形部分称为varnish的状态节点,又称为状态引擎,还有种叫法为varnish的内置函数。
图中红色的线条:没有查询缓存/缓存中数据过期/缓存中没有数据 情况下的流程
图中***的线条:直接将匹配数据通过内置函数vcl_pipe送往后台主机的流程
图中绿色的线条:查询缓存数据命中且数据没有过期/经后台主机返回的数据经被缓存后返回给客户流程
图中蓝色的线条:数据没有命中缓存向后台主机发出查询的流程
图中黑色的线条:数据从后台主机返回给varnish缓存的流程
图中内置函数的作用:
4.1)vcl_recv:用于接收和处理请求,请求到达并被成功接受后被调用。
四个主要用途:
修改客户端请求数据减少缓存对象差异性:比如删除URL中的www.字符
基于客户端数据选用缓存策略:不如不缓存POST请求,
为web应用程序执行URL重写规则
挑选合适的后端服务器
经常使用的终止语句:
pass:绕过缓存,不从缓存中查询内容或不将内容存储至缓存
pipe:不对客户端进行检查或做出任何操作,而是在客户端与后台服务间建立“管道“进行数据传输。
lookup:在缓存中查找用户请求的对象
error :格式:error code [reason] ,向客户端返回一个错误代码code 和 原因resion,该reason可自定义
4.2)vcl_pipe:将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容传递给客户端,直到这个链接被关闭。
经常使用的终止语句:
pipe:说明见上
error code [reason]:说明见上
4.3)vcl_hash: 在缓存中进行查询
4.4)vcl_hit:在缓存中找到请求的内容
经常使用的终止语句:
deliver:将找到的内容发送给客户端,把控制权交个函数vcl_deliver
error code [reason]:说明见上
pass:将控制权交个vcl_pass函数处理,可能是缓存中数据过期所致
4.5)vcl_miss:当在缓存中没有找到匹配数据时被调用
经常使用的结束语:
error code [reason]:说明见上
pass:说明见上
fetch:表示从后端获取的请求的内容,并将控制权交给VCL_fetch函数
4.6)vcl_pass:将请求直接传递给后端主机,后端主机将应答数据发送给客户端,而不执行缓存,每次都返回最新内容。
经常使用的结束语:
error code [reason]:说明见上
fetch:说明见上
4.7)vcl_fetch:向后端主机获取内容,通过判断将内容放入缓存,还是直接返回给客户端。
经常用的结束语:
error code [reason]:说明见上
deliver:将控制器交给vcl_deliver函数,将数据返回给客户端
hit_no_pass:不缓存数据,直接返回给客户端
4.8)vcl_deliver函数:将缓存中找到的数据返回给客户端
经常使用的结束语:
error code [reason]:说明见上
deliver:将内容返回给客户端
五 vcl语句的书写要素:
Varnish Configuration Language(vcl)是varnish配置的缓存策略工具。
是一种基于”域“的简单编程语言;
有内置的众多变量和 set 自定义变量可以使用;
支持if判断语句,不支持循环语句;
支持使用varnish内置函数的结束语,而没有返回值;
支持:=,==,~,!,&&,|| 逻辑操作符
使用://,#,/*comment*/ 表示注释
使用:sub $NAME { }用于定义函数
5.1) vcl编写的缓存策略---->management线程进行分析---->调用gcc编译器--->编译成二进制程序-->chaild/cache线程调用
5.2)vcl策略被编译使用的操作:
假设vcl策略被定义在/etc/varnish/default.vcl文件中,varnishadm命令在安装varnish后会生成。
#varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
>vcl.list
---->显示现在使用的或者可以使用的vcl 配置
>vcl.load test1 default.vcl
---->执行编译,加载/etc/varnish/default.vcl,并定义被编译后的vcl策略版本名为test1
>vcl.use test1
---->将varnish现在使用的vcl策略版本切换使用test1所代表的配置
>help
----->列出该模式下可以使用的命令
5.3)vcl中内置的变量(全面的内置变量请参考官方站点文档):
(1)在任何引擎中均可使用:
now:获取当前时间
.host:后端主机的主机名
.port:后端主机的端口号
(2)用于处理请求阶段:
client.ip:客户端IP地址
server.hostname:varnish的主机名
server.ip:varnish的ip地址
server.port:varnish的端口号
req.request:请求方法
req.url: 请求的URL
req.proto: HTTP协议版本
req.backend: 用于服务此次请求的后端主机;
req.backend.healthy: 后端主机健康状态;
req.http.HEADER: 引用请求报文中指定的首部;
req.can_gzip:客户端是否能够接受gzip压缩格式的响应内容;
req.restarts: 此请求被重启的次数;
(3)varnish向backend主机发起请求前可用的变量
bereq.request: 请求方法
bereq.url:请求的URL
bereq.proto:HTTP的协议版本
bereq.http.HEADER:请求报文中指定的首部
bereq.connect_timeout: 等待与backend主机建立连接的超时时长
(4)backend主机的响应报文到达本主机(varnish)后,将其放置于cache中之前可用的变量
beresp.do_stream: 流式响应;
beresp.do_gzip:是否压缩之后再存入缓存;
beresp.do_gunzip:是否不压缩就存入缓存
beresp.http.HEADER:
beresp.proto:
beresp.status:响应状态码
beresp.response:响应时的原因短语
beresp.ttl:响应对象剩余的生存时长,单位为second;
beresp.backend.name: 此响应报文来源backend名称;
beresp.backend.ip
beresp..backend.port
beresp.storage:将响应报文存储在指定的存储
(5)缓存对象存入cache之后可用的变量
obj.proto
obj.status:响应时的状态码
obj.response :响应是的原因短语
obj.ttl
obj.hits:缓存对象命中的次数
obj.http.HEADER
(6)在决定对请求键做hash计算时可用的变量
req.hash:以指定查询缓存的键做为hash计算的键;
(7)在为客户端准备响应报文时可用的变量
resp.proto
resp.status
resp.response
resp.http.HEADER
5.4)补充:
vcl书写的规则应用在varnish的状态节点上。
vcl节点间彼此有相关性,但是彼此互相隔离
vcl状态节点使用return(xxxx)来退出到varnish而非下一个状态节点
varnish有一个默认vcl配置文件,若管理员在定义规则时将各个状态节点规则写明,则使用默认的
vcl配置文件中定义的节点规则实施
六 varnish的后端存储
varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:
(1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);
(2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;
(3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;
varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。
选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。然而,需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。
七 简单的配置使用:
7.1)配置一个简单的varnish实例:
(1):设定vcl规则配置文件:
[root@Test01 source]# cd /etc/varnish/
[root@Test01 varnish]# ls
default.vcl secret
[root@Test01 varnish]# cp default.vcl test.vcl
[root@Test01 varnish]# vim test.vcl
backend backwebserver {
.host = "172.16.100.6";
.port = "80";
}
sub vcl_recv {
set req.backend = backwebserver;
}
* 在这个配置中只是设定了后端的webserver的地址,在varnish的 vcl_recv状态引擎上调用了一下
其它的vcl规则并没设定,varnish默认从/etc/varnish/default.vcl中加载
7.2)配置varnish实例,显示命中:
(1)上面的包头中并没有显示是否命中,修改下vcl规则
[root@Test01 varnish]# vim test.vcl
backend backwebserver {
.host = "172.16.100.6";
.port = "80";
}
sub vcl_recv {
set req.backend = backwebserver;
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "Hit from"+" "+server.ip;
} else {
set resp.http.X-Cache = "Miss via"+" "+server.ip;
}
}
7.3)配置varnish实例,让bbs/路径下文件的不缓存:
(1)后端主机上bss/index.html文件的设定:
[root@Test06 ~]# cd /var/www/html/bbs
[root@Test06 bbs]# ls
index.html
[root@Test06 bbs]# cat index.html
<h1>BBS 100.6</h1>
[root@Test06 bbs]# exit
logout
Connection to 172.16.100.6 closed.
[root@Test01 varnish]#
(2)修改vcl规则文件:
[root@Test01 varnish]# vim test.vcl
backend backwebserver {
.host = "172.16.100.6";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "^/bbs/") {
return(pass);
}
set req.backend = backwebserver;
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "Hit from"+" "+server.ip;
} else {
set resp.http.X-Cache = "Miss via"+" "+server.ip;
}
}
八 配置varnish支持后端多台服务器:
8.1)案例1:实现请求内容实现动静分离
[root@Test01 varnish]# vim test.vcl
backend bkws1 {
.host= "172.16.100.6";
.port= "80";
}
backend bkws2 {
.host= "172.16.100.7";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "\.php$") {
set req.backend = bkws1;
}
if (req.url~ "\.(html|css|js|jpg|jpeg|png|gif)$") {
set req.backend = bkws2;
}
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "Hitfrom"+" "+server.ip;
} else {
set resp.http.X-Cache = "Missvia"+" "+server.ip;
}
}
8.2)案例2,让后台支持个服务器
[root@Test01 varnish]# vim test.vcl
backend bkwb1{
.host = "172.16.100.6";
.port = "80";
}
backend bkwb2{
.host = "172.16.100.7";
.port = "80";
}
director webserver random {
{ .backend = bkwb1; .weight = 1; }
{ .backend = bkwb2; .weight = 1; }
}
sub vcl_recv {
set req.backend = webserver;
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "Hit from"+" "+server.ip;
} else {
set resp.http.X-Cache = "Miss via"+" "+server.ip;
}
}
九 配置对后端主机进行健康状态检测
[root@Test01 varnish]# vim test.vcl
7 probe hc {
8 .url = "/index.html";
9 .interval = 60s;
10 .timeout = 0.3s;
11 .window = 8;
12 .threshold = 3;
13 .initial = 3;
14 .expected_response = 200;
15 }
16 backend bkwb1{
17 .host = "172.16.100.6";
18 .port = "80";
19 .probe = bc;
20 }
21 backend bkwb2{
22 .host = "172.16.100.7";
23 .port = "80";
24 .probe = bc;
25 }
Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判, Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。每个后端服务器当前探测的健康状态探测方法通过.probe进行设定。
.probe中的探测指令常用的有:
(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;
(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close";
(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;
(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;
(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;
(6) .expected_response:期望后端主机响应的状态码,默认为200;
(7) .interval:探测请求的发送周期,默认为5秒;
(8) .timeout:每次探测请求的过期时长,默认为2秒;