一、前言
首先来简单认识一下什么是varnish?它能实现什么样的功能?.......
Varnish是一款高性能的开源HTTP加速器,常见的缓存服务开源解决方案有varnish、nginx、squid 、ats等,Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开 发者之一,varnish项目是2006年发布的第一个版本0.9.距今已经有十年了,此文档之前也提过varnish还不稳定,那是2007年时候编写的,经过varnish开发团队和网友们的辛苦耕耘,现在的varnish已经很健壮。很多门户网站已经部署了varnish,并且反应都很好,甚至反应比squid还稳定, 且效率更高,资源占用更少。挪威最大的在线报纸 Verdens Gang 使用3台Varnish代替了原来的12台Squid,性能比以前更好。相信在反向代理,web加速方 面,varnish已经有足够能力代替squid。
二、varnish有哪些特性
1、Varnish的稳定性很高,两者在完成相同负荷的工作时,Squid服务器发生故障的几率要高于Varnish,因为使用Squid要经常重启;
2、Varnish访问速度更快,因为采用了“Page Cache”技术,所有缓存数据都直接从内存读取(映射),而squid是从硬盘读取,因而Varnish在访问速度方面会更快;
3、Varnish可以支持更多的并发连接,因为Varnish的TCP连接释放要比Squid快,因而在高并发连接情况下可以支持更多TCP连接;
4、Varnish可以通过管理端口,使用正则表达式批量的清除部分缓存,而Squid是做不到的;
5、squid属于是单进程使用单核CPU,但Varnish是通过fork形式打开多进程来做处理, 所以可以合理的使用所有核来处理相应的请求。
三、Varnish的安装方式
Varnish的安装非常简单,常用的两种方式有yum安装和源码包安装,下面一源码安装来简单介绍:
1、安装前的准备
获取varnish软件
Varnish的官方站点为http://varnish-cache.org,这里面有varnish的最新说明文档,以及版本升级记录,从此站点可以找到varnish在SourceForge的下载链接,目前,varnish的最新版本是Varnish 2.1.2,下载完成后的包名为varnish-2.1.2.tar.gz,此处我们就以此版本为例,进行安装配置。
2、建立varnish用户以及用户组,并且创建Varnish缓存目录和日志目录:
[root@varnish-server ~]#useradd -s /sbin/nologin varnish
[root@varnish-server ~]#mkdir /data/varnish/cache
[root@varnish-server ~]#mkdir /data/varnish/log
[root@varnish-server ~]#chown -R varnish:varnish /data/varnish/cache
[root@varnish-server ~]#chown -R varnish:varnish /data/varnish/log
3、安装varnish(在此之前最好安装yum包组和pcre-devel、openssl-devel,否则编译时易出错)
这里我们将varnish安装编译到/usr/local/目录下,操作如下:
[root@varnish-server ~]#tar -zxvf varnish-2.1.2.tar.gz
[root@varnish-server ~]#cd varnish-2.1.2
[root@varnish-server ~]#./configure --prefix=/usr/local/varnish \
>--enable-dependency-trackin
>--enable-debugging-symbols
>--enable-developer-warnings
[root@varnish-server ~]#make
[root@varnish-server ~]#make install
至此,varnish安装完毕。
四、配置Varnish
VCL使用说明
VCL,即为Varnish Configuation Language,用来定义varnish的存取策略,VCL语法比较简单,跟C和perl比较相似,可以使用指定运算符“=”,比较运算符“==”,逻辑运算符“!,&&,!!”等形式。还支持正则表达样和用“~”进行ACL匹配运算,同时还可以使用“set”这样的关键字来指定变量。
需要注意的是,“\”字符在VCL里没有特别的含义,这点与其它语言略有不同,另外,VCL只是配置,并不是真正的编程语言,没有循环,也没有自定义变量。
在讲述Varnish配置之前,首先需要了解下varnish的配置语法,即VCL,下面对VCL常用的一些内置函数和公用变量进行详细介绍。
五、VCL状态
1、VCL有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离;每个状 态引擎可使用return(x)指明关联至哪个下一级引擎;每个状态引擎对应于vcl文件中的一个配置段
vcl_recv:接受用户请求进varnish的入口的引擎,接受到结果之后,利用 return(lookup),将请求转交给vcl_hash引擎进行处理
vcl_hash:接受到用户请求后,对用户请求的URL进行hash计算,根据请求的首 部信息,以及hash结果进行下一步处理的引擎
vcl_hit:经过vcl_hash引擎处理后,发现用户请求的资源本地有缓存,则 vcl_hash引擎通过return(hit)将请求交给vcl_hit引擎进行处理,vcl_hit引擎处理后 将请求交给vcl_deliver引擎,vcl_deliver引擎构建响应报文,响应给用户
vcl_miss:经过vcl_hash引擎处理后,发现用户请求的资源本地没有缓存,则 vcl_hash引擎通过return(miss)将请求交给vcl_miss引擎进行处理
vcl_purge:经过vcl_hash引擎处理后,发现请求是对缓存的内容进行修剪时,则通过 return(purge)交给vcl_purge引擎进行处理,vcl_purge引擎处理后,利用vcl_synth引擎将处 理的结果告知给用户
vcl_pipe:经过vcl_hash引擎处理后,发现用户请求的报文varnish无法理解,则通过 return(pipe),将请求交给vcl_pipe引擎,pipe引擎直接将请求交给后端真实服务器
vcl_pass:当请求经过vcl_hash处理后,发现请求报文不让从缓存中进行响应或其他原因没办 法查询缓存,则由return(pass)或return(hit-for-pass)交由vcl_pass引擎进行处理
vcl_backend_fetch:当发现缓存未命中或由vcl_pass传递过来的某些不能查询缓存的请求, 交由vcl_backend_fetch引擎处理,vcl_backend_fetch引擎会向后端真实web服务器发送请 求报文,请求对应的资源
vcl_backend_response:当后端发送响应报文到varnish后,会由vcl_backend_resonse引 擎进行处理,如:判断响应的内容是否可缓存,如果能缓存,则缓存下来后,交给vcl_deliver 引擎,如果不能缓存,则直接交给vcl_deliver引擎,vcl_deliver引擎构建响应报文给客户端
varnish4.0版本的两个特殊的引擎
vcl_init:在处理任何请求之前要执行的vcl的代码,主要用于初始化VMOD,可 用在后端主机有多台时,借助此引擎完成多台主机的负载均衡效果
vcl_fini:所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMOD
2、VCL处理流程图
通过上面对VCL的介绍,读者对各个函数实现的功能已经有了一个了解,其实每个函数之间都是相互关联的,下图列出了varnish处理HTTP请求的一个运行流程图。
处理过程大致分为如下几个步骤:
(1)Receive状态,也就是请求处理的入口状态,根据VCL规则判断该请求应该是Pass或Pipe,或者进入Lookup(本地查询)。
(2)Lookup状态,进入此状态后,会在hash表中查找数据,若找到,则进入Hit状态,否则进入miss状态。
(3)Pass状态,在此状态下,会进入后端请求,即进入fetch状态。
(4)Fetch状态,在Fetch状态下,对请求进行后端的获取,发送请求,获得数据,并进行本地的存储。
(5)Deliver状态, 将获取到的数据发送给客户端,然后完成本次请求。
3、内置公用变量
VCL内置的公用变量可以用在不同的VCL函数中,根据这些公用变量使用的不同阶段,下面依次介绍。
当请求到达后,可以使用的公用变量如表1所示:
表1
公用变量名称 含义
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 在向后端主机请求时,可以使用的公用变量如表2所示:
表2
公用变量名称 含义
beresp.request 指定请求的类型,例如GET、HEAD等
beresp.url 指定请求的地址
beresp .proto 表示客户端发起请求的HTTP协议版本
beresp .http.header 表示对应请求中的http头部信息
beresp .ttl 表示缓存的生存周期,也就是cache保留多长时间,单位是秒
从cache或者后端主机获取内容后,可以使用的公用变量如表3所示:
表3
公用变量名称 含义
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 表示返回上一次请求到现在的间隔时间,单位是秒
对客户端应答时,可以使用的公用变量如表4所示:
表4
公用变量名称 含义
resp.status 表示返回给客户端的HTTP状态代码
resp.proto 表示返回给客户端的HTTP协议版本
resp.http.header 表示返回给客户端的HTTP头部信息
resp.response 表示返回给客户端的HTTP状态信息
在上面的讲述中,我们只是介绍了常用的VCL内置公用变量,如果需要了解和使用更多的公用变量信息,请登录varnish官方网站查阅。
六、Varnish 的 Storage 方式可分为两种:
(1)Malloc 通过 malloc 获取内存;
(2)Mmap file 创建大文件,通过二分法分段映射成 1G 以内的大块。
以 Mmap file 的缓存方式启动 I/O 也会形成瓶颈,原因主要是 Varnish 缓存的数据先会刷到磁盘上,然后在一次性读到内存中,这在访问量大的时候同时也会对 I/O 造成很大的压力。Malloc 缓存方式虽然对 I/O 没有压力,因所有缓存数据都写到内存中。
七、配置一个简单的Varnish实例
由于版本的不同,Varnish配置文件的写法也存在一定差异,这里讲述的版本是基于centos 7.3版本的varnish4.0,但是该配置文件一定要以非注释行vcl 4.0开始,否则服务将不能识别。
Varnish安装完成后,默认的配置文件为/usr/local/varnish/etc/varnish/default.vcl,配置完成的default.vcl文件如下:
vcl 4.0; ##############启用负载均衡模块############### import directors; ##############配置健康状态探测############## probe backend_healthcheck { .url = "/index.html"; .window = 5; #窗口 .threshold = 2; #门槛 .interval = 3s; .timeout = 1s; } #############添加后端主机################ backend web1 { .host = "172.17.254.17"; .port = "80"; .probe = backend_healthcheck; } backend img1 { .host = "172.17.254.107"; .port = "80"; .probe = backend_healthcheck; } #############定义负载均衡及算法############### sub vcl_init { new web_cluster = directors.random(); web_cluster.add_backend(web1,10); new img_cluster = directors.round_robin(); img_cluster.add_backend(img1); } ################定义Purge-ACL控制####################### acl purgers { # 定义可访问来源IP "127.0.0.1"; "172.17.0.0"/16; } ################定义vcl_recv函数段###################### sub vcl_recv { if (req.method == "GET" && req.http.cookie) { return(hash); } #####如果请求不是GET或者HEAD,不缓存###### if(req.method!="GET"&&req.method!="HEAD"){ return(pass); } #####不正常的请求不缓存##### if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "PURGE" && req.method != "DELETE") { return (pipe); } if (req.url ~ "index.php") { return(pass); } if (req.method == "PURGE") { # PURGE请求的处理 if (client.ip ~ purgers) { # return(synth(405,"Method not allowed")); return(purge); } } ##为发往后端主机的请求添加X-Forward-For首部## if (req.http.X-Forward-For) { set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip; } else { set req.http.X-Forward-For = client.ip; } #####实现动静分离##### set req.http.X-Forward-For=client.ip; if(req.url~"(?i)\.(jpeg|jpg|png|jif)($|\?)"){ set req.backend_hint=img_cluster.backend(); } ####################定义vcl_hash函数段################# if (req.http.host ~ "(?i)^(www.)?aaa.com$") { # 根据不同的访问域名,分发至不同的后端主机组 set req.backend_hint = web_cluster.backend(); } elsif (req.http.host ~ "(?i)^images.aaa.com$") { set req.backend_hint = img_cluster.backend(); } return(hash); } sub vcl_hash { hash_data(req.url); } ##############设置资源缓存时长################# sub vcl_backend_response { # 自定义缓存文件的缓存时长,即TTL值 if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") { set beresp.ttl = 10s; } if (bereq.url ~ "\.(html|css|js)$") { set beresp.ttl = 1200s; } # if (beresp.http.Set-Cookie) { # 定义带Set-Cookie首部的后端响应不缓存,直接返回给客户端 set beresp.grace = 30m; return(deliver); # } } sub vcl_deliver { if (obj.hits > 0) { # 为响应添加X-Cache首部,显示缓存是否命中 set resp.http.X-Cache = "HIT from " + server.ip; } else { set resp.http.X-Cache = "MISS"; } unset resp.http.X-Powered-By; unset resp.http.Via; }
在经过以上的配置之后会出现一下测试界面:
本文出自 “Linux探索之旅” 博客,请务必保留此出处http://jieruma.blog.51cto.com/13158701/1981815
原文地址:http://jieruma.blog.51cto.com/13158701/1981815