varnish

来源:互联网 发布:凯文先生的淘宝店 编辑:程序博客网 时间:2024/06/05 13:23



         程序的运行具有局部性特征:时间局部性:一个数据被访问过之后,可能很快会被再次访问到;空间局部性:一个数据被访问时,其周边的数据也有可能被访问到。这使得数据具有热区,varnish缓存服务器正是利用这个特点实现加速访问的目的。

一 varnish简介

1 varnish程序架构


varnish程序包含两类进程:

主控进程Manager:
(1)提供命令行接口,有专门的工具,交互式运行
(2)管理子进程
(3)初始化:程序初始化、缓存系统初始化
(4)加载缓存控制的配置文件

子进程Cacher,包含多种类型的线程:accept(接收请求), worker, expiry(处理过期请求)...:
(1)与命令行接口进行交互
(2)s/h管理缓存存储空间,查找缓存是否命中
(3)记录日志、记录统计数据
(4)接受客户端请求
(5)与后端服务器通信
(6)工作进程负责处理请求
(7)缓存项过期清理

2  varnish的程序环境

/etc/varnish/varnish.params: 配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
/etc/varnish/default.vcl:配置各Child/Cache线程的缓存策略;
/usr/sbin/varnishd:主程序
/usr/bin/varnishadm:CLI interface命令行接口
Shared Memory Log共享内存日志交互工具(
为避免日志成为性能瓶颈,将日志直接记录于内存,有固定大小,一旦空间用尽,就会覆盖原有日志):

/usr/bin/varnishhist
/usr/bin/varnishlog
/usr/bin/varnishncsa

/usr/bin/varnishstat

/usr/bin/varnishtop

/usr/bin/varnishtest:测试工具程序

/usr/sbin/varnish_reload_vcl:VCL配置文件重载程序
/usr/lib/systemd/system/varnish.service:varnish服务
/usr/lib/systemd/system/varnishlog.service:日志持久的服务
/usr/lib/systemd/system/varnishncsa.service:日志持久的服务

3 varnish的缓存存储机制

· malloc[,size]
内存存储,[,size]用于定义空间大小;重启后所有缓存项失效;
· file[,path[,size[,granularity]]]
磁盘文件存储,黑盒;重启后所有缓存项失效;
· persistent,path,size
文件存储,黑盒;重启后所有缓存项有效;处于实验阶段;

4 varnish状态引擎


varnish3.0的请求处理架构大致可以总结为:

varnish收到客户端请求后,判断能否缓存:
若不允许,则通过vcl_pass直接到后端服务器获取资源
若允许,则进行哈希,并判断缓存是否命中:
若命中,则直接封装响应报文并返回给客户端
若未命中,则直接到后端服务器获取资源
对后端服务器的响应报文,判断资源是否允许缓存(查看服务器发送的响应报文首部的no-cache、no-storege等字段,判断后端服务器是否允许缓存服务器缓存该资源):
若允许,则先缓存再响应给客户端;
若不允许,则直接响应给客户端。

 

         在builtin.vcl即系统内建的vcl中定义了状态引擎vcl_recv :

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);

}

}

          与上图对比,可以发现上图是十分准确,按照builtin.vcl的定义,vcl_recv之后大致分为vcl_hash、vcl_pipe、vcl_purge、wait,varnish4.0的请求处理架构大致可以总结为:

         varnish收到客户端请求后,

          1. 如果是标准的http协议请求报文,判断缓存对象是否需要进行修剪(通过看请求报文的请求方法是否为purge

(1)若不需要进行修剪,判断能否缓存(涉及登录验证或cookies信息的一般不允许在缓存服务器进行缓存,缓存服务器本地没有该类资源;get、head方法才可缓存,其他方法如put不可缓存):

若不允许,则varnish缓存服务器通过vcl_pass直接到后端服务器获取资源

若允许,则进行哈希,判断缓存是否命中:

若命中,则varnish缓存服务器封装响应报文并返回给客户端或者到后端服务器确认当前缓存是否过期(有些资源客户端允许varnish缓存服务器以本地缓存响应,但是要求其必须到后端服务器确认缓存是否过期);

若未命中,则varnish缓存服务器直接到后端服务器获取资源
后端服务器的响应报文可能是超时等异常响应或正常响应,若为正常响应,则判断资源是否允许缓存(查看服务器发送的响应报文首部的no-cache、no-storege等字段,判断后端服务器是否允许缓存服务器缓存该资源):
若允许,则先缓存再响应给客户端;
若不允许,则直接响应给客户端。

(2)若需要进行修剪,则执行修剪操作;

         2.如果是非标准的http协议的请求报文,varnish收到该请求后无法理解并处理,只能转为四层代理,建立管道,直接将请求转到后端服务器

           3.缓存服务器连接超时

二 varnish缓存配置

示例1 强制对某类资源的请求不检查缓存:

vcl_recv {

if (req.url ~ "(?i)^/(login|admin)") {

return(pass);

}

}

        当客户端访问的url为login或admin时,不允许varnish缓存服务器以本地缓存响应,而是由varnish缓存服务器到后端服务器获取资源后封装响应报文再返回给客户端,且不允许varnish缓存服务器将该资源缓存到本地,即当客户端再次请求此类资源时,varnish缓存服务器还要到后端服务器去获取资源。

示例2 对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由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;

}

}

       为了追踪用户信息,使用cookies机制,即客户端访问时会携带cookie,在bulitin.vcl

if (req.http.Authorization || req.http.Cookie) {

/* Not cacheable by default */

return (pass);

}

       中定义了若用户的请求报文中包含用户验证或cookie信息,则不予缓存,即varnish缓存服务器只能代替客户端到后端服务器获取资源并直接返回给客户端,而不能缓存这两类url对应的资源。若不进行设置,即使携带cookie的客户端访问的是电商站点某品牌的宣传图片,varnish缓存服务器也不能进行缓存,也要到后端服务器去获取资源。若后端服务器响应报文的cache-control中包含s-maxage(公共缓存标识)字符串,即允许varnish缓存该资源,则可以缓存不用处理;若后端服务器响应报文的cache-control中不包含s-maxage(公共缓存标识)字符串,即不允许varnish缓存该资源,且该资源是可公开的图片一类的资源,可以取消该响应报文中的私有标识Set-Cookie,并设定缓存时间,就可将该资源缓存到varnish本地。

        客户端请求到达Nginx时,Nginx解封装请求数据包,获得客户端的需求后,若有客户端所请求的资源则直接封装响应报文并返回给客户端,若没有,则到后端服务器去获取相应资源(由Nginx亲自发起请求,数据包的源地址是Nginx代理服务器的地址不是客户端的地址,即Nginx重新封装了数据包,所以后端服务器看到的地址是Nginx代理服务器的地址不是客户端的地址),获取到后缓存到本地并封装响应报文返回给客户端(由Nginx封装响应包,数据包的源地址是Nginx代理服务器的地址不是后端服务器的地址,所以后端服务器看到的地址是Nginx代理服务器的地址不是后端服务器的地址) ,所以Nginx是代理而不是转发。
        客户端请求到达varnish时,varnish解封装请求数据包,获得客户端的需求后,首先看客户端是否允许缓存,(查看客户端发送的请求报文首部的no-cache、no-storege等字段,判断客户端是否允许缓存服务器以缓存响应其请求的资源)即客户端是否允许以缓存响应:若不允许,则通过vcl_pass直接到后端服务器获取资源(由varnish亲自发起请求,数据包的源地址是varnish缓存服务器的地址不是客户端的地址,即varnish重新封装了数据包,所以后端服务器看到的地址是varnish缓存服务器的地址不是客户端的地址)。获取到后,看后端服务器是否允许缓存,若允许则缓存到本地并封装响应报文返回给客户端(由varnish缓存服务器封装响应包,数据包的源地址是varnish缓存服务器的地址不是后端服务器的地址,所以客户端看到的地址是varnish缓存服务器的地址不是后端服务器的地址) ;若不允许,则直接封装响应报文返回给客户端。若允许,则判断缓存是否命中:若命中,则直接封装响应报文(由varnish缓存服务器封装响应包,数据包的源地址是varnish缓存服务器的地址不是后端服务器的地址,所以客户端看到的地址是varnish缓存服务器的地址不是后端服务器的地址,这种情形下后端服务器根本就收不到客户端的请求包) 并返回给客户端或者到后端服务器确认当前缓存是否过期(客户端允许以缓存响应但是要求varnish缓存服务器必须确认是否过期)若未命中,则直接到后端服务器获取资源(由varnish亲自发起请求,数据包的源地址是varnish缓存服务器的地址不是客户端的地址,即varnish重新封装了数据包,所以后端服务器看到的地址是varnish缓存服务器的地址不是客户端的地址)。获取到后,看后端服务器是否允许缓存,若允许则缓存到本地并封装响应报文返回给客户端(由varnish封装响应包,数据包的源地址是varnish缓存服务器的地址不是后端服务器的地址,所以客户端看到的地址是varnish缓存服务器的地址不是后端服务器的地址) ;若不允许,则直接封装响应报文返回给客户端。
        Nginx充当反向代理其本机一般是没有客户端所请求的资源的,而varnish缓存服务器其本机一般是有客户端所请求的资源的。

示例3 缓存对象的修剪:

        过期机制:服务器发给客户端的响应报文中定义了资源的缓存有效期,在有效期内客户端浏览器以本地缓存进行响应,而不去服务器请求资源。存在的问题:缓存内容还未过期但是后端服务器的资源已更新,varnish只能使用过期资源响应客户端请求;缓存内容已过期但后端服务器的资源还未更新,varnish也会到后端服务器去请求资源
        条件式缓存:服务器发给客户端的响应报文中定义了资源的缓存有效期和E-tag,客户端在发送资源请求数据包前先发送请求包 确认缓存是否过期,若过期才发送资源请求数据包
         varnish缓存服务器中采用了过期机制与条件式缓存相结合的方式,若缓存内容已过期,varnish会先发送验证资源是否过期的请求包到后端服务器,若后端服务器的资源还未更新,则varnish就不会到后端服务器去请求资源,解决了过期机制的第二个问题;将缓存有效期的时间缩短,可以一定程度上解决过期机制的第一个问题,但是仍然存在缓存内容还未过期但是后端服务器的资源已更新,varnish只能使用过期资源响应客户端请求的情况,此时可以执行修剪操作。

          (1) 怎样执行purge操作

sub vcl_purge {

return (synth(200,"Purged"));

}

(2) 何时执行purge操作

sub vcl_recv {

if (req.method == "PURGE") {

return(purge);

}

...

}

客户端请求curl -X PURGE http://192.168.25.107/a.jpg带有PURGE方法,varnish收到后由synth封装响应报文,返回200的响应码和"Purged"字符串,就完成了修剪操作。为防止恶意攻击,可以通过acl添加此类请求的访问控制法则:

acl purgers {
"127.0.0.0"/8;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return(synth(405,"Purging not allowed for " + client.ip));
}
return(purge);
}
...
}
        只允许127.0.0.0/8执行修剪操作

purge每次只能修剪一个url对应的资源,ban每次能修剪一类url对应的资源:

        在varnishadm中:

        ban <field> <operator> <arg>
       示例:ban req.url ~ ^/.jpg
       当客户端访问请求的url以.jpg结尾时,执行修剪操作

原创粉丝点击