Varnish是一款高性能的开源HTTP加速器
Varnish与一般服务器软件类似,分为master(management)进程和child(worker,主要做cache的工作)进程。master进程读入命令,进行一些初始化,然后fork并监控child进程。child进程分配若干线程进行工作,主要包括一些管理线程和很多woker线程。
针对文件缓存部分,master读入存储配置(-sfile[,path[,size[,granularity]]]),调用合适的存储类型,然后创建/读入相应大小的缓存大文件。接着,master初始化管理该存储空间的结构体。这些变量都是全局变量,在fork以后会被child进程所继承(包括文件描述符)。
在child进程主线程初始化过程中,将前面打开的存储大文件整个mmap到内存中(如果超出系统的虚拟内存,mmap失败,进程会减少原来的配置mmap大小,然后继续mmap),此时创建并初始化空闲存储结构体,挂到存储管理结构体,以待分配。
接着,真正的工作开始,Varnish的某个负责接受新HTTP连接的线程开始等待用户,如果有新的HTTP连接过来,它总负责接收,然后叫醒某个等待中的线程,并把具体的处理过程交给它。Worker线程读入HTTP请求的URI,查找已有的object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。
分配缓存的过程是这样的:它根据所读到object的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个object的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据LRU机制,把最旧的object释放掉。
释放缓存的过程是这样的:有一个超时线程,检测缓存中所有object的生存期,如果超初设定的TTL(TimeToLive)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。
整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的object都考虑是在内存中,如果系统内存不足,系统会自动将其换到swap空间,而不需要varnish程序去控制。
[root@lab1 varnish]# ls ~/varnish/ 3.0.5 varnish-libs-3.0.4-1.el6.x86_64.rpm varnish-3.0.4-1.el6.x86_64.rpm varnish-libs-devel-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpm [root@lab1 varnish]# yum install varnish*.rpm #编辑/etc/sysconfig/varnish,将监听端口改为80 VARNISH_LISTEN_PORT=80 #编辑/etc/varnish/default.vcl,将监听服务器妨碍为172.16.21.102:80 backend default { .host = "172.16.21.102"; .port = "80"; } #启动服务 service varnish start
#此时我们已经可以访问arnish服务器172.16.21.101了
现在我们可以使用varnishadmin来配置varnish了
[root@node0 varnish]# varnishadm
#拷贝default.vcl到test1.vcl co default.vcl test1.vcl #编辑tes1.vcl在sub vcl_deliver段中添加 sub vcl_deliver { if(obj.hits>0){ #如果命中次数大于0 set resp.http.X-Cache = "HIT"; }else{ set resp.http.X-Cache = "MISS"; } return (deliver); } #加载并启用test1.vcl varnish> vcl.load test ./test1.vcl 200 VCL compiled. varnish> vcl.use test 200
访问测试,没有命中
再次访问,可以看到已经命中
再次编辑test1.vcl.添加如下内容
sub vcl_recv { if (req.url ~ "miss.html"){ #如果url被miss.html匹配,不要缓存,直接进入pass return(pass); } return (lookup); } #加载配置 varnish> vcl.load test2 ./test1.vcl 200 VCL compiled. varnish> vcl.use test2 200 #在102添加miss.html文件 [root@lab2 html]# echo "<h1>Can't be Cached</h1>" > miss.html
访问miss.html,可见无论如何刷新都不会命中缓存
sub vcl_fetch { if (req.url ~ "\.(jpg|jpeg|gif|png)"){ #如果文件以指定格式结尾,使其缓存两个小时 set beresp.ttl=7200s; unset beresp.http.Set-Cookie; } }
#修改配置文件 [root@lab1 varnish]# cat /etc/varnish/test1.vcl |grep -v "^#" backend default { .host = "172.16.21.102"; .port = "80"; } acl purgers { #访问控制列表 "127.0.0.1"; "172.16.21.0"/24; } sub vcl_recv { if (req.request == "PURGE"){ #如果请求方法为PURGE并且 if(! client.ip ~ purgers) { #客户端ip不在列表中 error 406 "Method not allowed IN the address"; #生成错误报文并退出 } if (req.url ~ "miss.html"){ return(pass); } } return (lookup); } sub vcl_pass { if(req.request == "PURGE") { error 502 " Purge on a passwd object"; } return (pass); } sub vcl_hit { if(req.request == "PURGE") { purge; error 201 " Purged"; } return (deliver); } sub vcl_miss { if(req.request == "PURGE") { purge; error 405 " Not Found in Cache"; } return (fetch); } sub vcl_fetch { if (req.url ~ "\.(jpg|jpeg|gif|png)"){ set beresp.ttl=7200s; unset beresp.http.Set-Cookie; } } sub vcl_deliver { if(obj.hits>0){ set resp.http.X-Cache = "HIT"; }else{ set resp.http.X-Cache = "MISS"; } return (deliver); } #修剪测试 [root@lab1 varnish]# curl -X PURGE 172.16.21.101 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>201 Purged</title> </head> <body> <h1>Error 201 Purged</h1> Purged <h3>Guru Meditation:</h3> XID: 587750580 <hr> Varnish cache server </body> </html> [root@lab1 varnish]# curl -X PURGE 172.16.21.101/miss.html <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>502 Purge on a passwd object</title> </head> <body> <h1>Error 502 Purge on a passwd object</h1> Purge on a passwd object <h3>Guru Meditation:</h3> XID: 587750582 <hr> Varnish cache server </body> </html>
#编辑配置文件 [root@lab1 varnish]# cat /etc/varnish/test1.vcl |grep -v "^#" backend web1 { .host = "172.16.21.102"; .port = "80"; } backend web2 { .host = "172.16.21.103"; .port = "80"; } director webservers random { .retries = 5; { .backend = web1; .weight = 2 ; } { .backend = web2; .weight = 3 ; } } ... sub vcl_recv { set req.backend = webservers; } return (lookup); } #重新加载并使用 varnish> vcl.load test9 ./test1.vcl 200 VCL compiled. varnish> vcl.use test9 200
#访问测试
#清除缓存后访问,
curl -X PURGE 172.16.21.101/