varnish 简介
varnish是一款强大的http加速器,其设计初衷因为计算机越来越复杂,不像那个只有内存与硬盘的存储媒介的年代,如今的计算机系统除了内存外还有cpu的L1、L2、L3快取,因此当初的Squid cache自行处理物件替换的架构不可能得知这些情况而做到最佳,但操作系统可以得知该情况,此PoulHenning Kamp设计了varinish的架构
varnish术语解析
缓存的衡量参数:命中率 # 1 文档命中率 # 2 字节命中率 缓存类型: # 私有缓存 (比如客户端的浏览器上的缓存) # 公共缓存 (比如一个组织机构建立的缓存服务器) 缓存的层次结构 #客户端 <---...-->2级代理<--------->1级代理 <----------->原始服务器
内容路由 #ICP : Internet Cache Protocol 互联网缓存协议 #CARP: Cache Array Routing Protocol 缓存阵列路由协议---用的比较多
缓存处理客户端请求的具体步骤 #接受请求 #解析请求 (代理的功能) #查询缓存 (检查本地缓存中是否存在对方请求的内容的副本) #副本的新鲜度检测 (检查本地缓存的副本是否为最新版本) #构建响应 (代理的功能---作为某个应用程序的代理服务器) #发送 #日志
保证副本的新鲜度? # 文档过期机制:-----------响应首部 HTTP/1.0 : Expires (过期时间) 绝对时间 -----比如2014年5月5日过期 HTTP/1.1 :Cache-Control (max-age=) 相对时长 ------比如还有100小时可用 # 条件式请求: --------------请求首部 1 mtime: If-Modified-Since 基于时间的条件式请求 2 ETag :If-None-Match 基于拓展标签条件式请求
原始服务器、缓存服务器、客户端 如何实现对缓存的控制 (1) 原始服务器或缓存服务器控制缓存的能力 # 由原始服务器定义: Cache-Control Cacmax-age =(属于私有缓存中) s-maxage =(属于公共缓存中) no-store :不能缓存 no-cache :能缓存下来,但不能直接使用此缓存对象; 缓存对象在使用之间必须做 新鲜度验证 must-revalidate:必须进行新鲜度验证 private : 客户端的私有数据,不缓存 public : 公共数据,缓存 #原始服务器不添加任何控制机制,而由缓存服务器自己决定缓存时长 (2)客户端对缓存使用情况的控制 # 客户端控制是否使用缓存: Cache-Control: max-stale:告知缓存机制可以使用过期的文件 no-cache :告知缓存机制必须进行验证,否则不会接受任何缓存文档; no-store :告知缓存机制必须尽快删除缓存中的文档
Varnish 基本架构
如上图所示: (1) varnish主要运行两个进程: Management进程和Child进程(也叫Cache进程)。 # Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。 # Child进程包含多种类型的线程 # Accept线程:接收新的连接请求并响应; # Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多; # Expiry线程:从缓存中清理过期内容;
(2)varnish日志 #为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log) #共享内存日志大小一般为80M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。
(3)VCL # Varnish Configuration Language (VCL)是varnish配置缓存策略的工具 # 使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用 # 整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成 VCL语法 # (1)//、#或/* comment */用于注释 # (2)sub $name 定义函数 ---即定义子例程 # (3)不支持循环,有内置变量 # (4)使用终止语句,没有返回值 # (5)域专用 # (6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)
(4)varnish后端存储 # 1)file:使用特定的文件存储全部的缓存数据; # 2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象; # 3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;
状态引擎(子例程)
VCL中由多个子例程组成,各个子例程之间有必然的关系,如下图所示
如上图 pipe 、lookup、pass 为vcl_recv 子例程的返回状态。依据此状态来判断下一步的去向
VCL中的变量
Varnish的安装配置
环境搭建
如上图 varnish服务器 172.16.13.2 外网网卡 192.168.20.11 内网网卡 后端服务器两个 192.168.20.12 服务器一内网地址 192.168.20.13 服务器二内网地址
准备工作
1 配置以上三台服务器的ip地址,此处不做详解 2 server1服务器 编辑web页面 #vim /var/www/html/index.html <h1>node12.linux.com</h1> #service httpd start 3 server2服务器 编辑web页面 #vim /var/www/html/index.html <h1>node13.linux.com</h1> #service httpd start
安装varnish并配置
1)下载3.0版本的varnish varnish-3.0.4-1.el6.x86_64.rpm varnish-libs-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpm 2)安装 # rpm -ivh varnish*.rpm 安装以上三个包 # rpm -ql varnish 3)编辑varnish配置文件,定义varnish启动时的特性 #vim /etc/sysconfig/varnish NFILES=131072 打开的最大文件数 MEMLOCK=82000 默认分配给日志log的内存数82M NPROCS="unlimited" 最大线程数 ,无限制 RELOAD_VCL=1 重新启动服务时候,是否重新编译vcl 重新使用vcl VARNISH_VCL_CONF=/etc/varnish/default.vcl vcl配置缓存策略的配置文件 VARNISH_LISTEN_PORT=80 varnish侦听的默认端口为6081,接受用户请求 ----------一般更改为80端口 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 varnish管理侦听的地址 VARNISH_ADMIN_LISTEN_PORT=6082 varnish管理接口, VARNISH_SECRET_FILE=/etc/varnish/secret 进入varnish管理接口的密钥文件 VARNISH_MIN_THREADS=50 最小线程数 VARNISH_MAX_THREADS=1000 最大线程数---------varnish超过5000个线程后会不稳定 VARNISH_THREAD_TIMEOUT=120 空闲线程转向工作线程的延迟时间 VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin 基于文件存储时的文件路径 VARNISH_STORAGE_SIZE=1G 后端存储的的大小 VARNISH_STORAGE="malloc,100M" 自定义内存大小 VARNISH_TTL=120 请求后端服务器的超时时间 4)启动服务 # service varnish start # ss -ntlp | grep 80
5 ) 进入varnish管理界面 #varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 varnish> help --------查看一下所有的命令参数 200 help [command] ping [timestamp] auth response quit banner status start stop vcl.load <configname> <filename> 加载编译某个vcl,加载的时候并指定一个配置名称(该名称随意指定) vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> vcl.discard <configname> vcl.list 列出所有的vcl vcl.show <configname> 查看已经列出的vcl param.show [-l] [<param>] param.set <param> <value> panic.show panic.clear storage.list
6 ) 创建vcl文件 #vim /etc/varnish/test.vcl 内容如下 backend websrv1 { .host = "192.168.20.12"; .port = "80"; } 进入管理界面编译使用 #varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 varnish> vcl.load test2 test.vcl ------------------加载编译test.vcl 200 VCL compiled. varnish> vcl.use test2 -----------------使用已经编译好 test.vcl 200 varnish> vcl.show test2 ------------------查看test.vcl 的内容 200 backend websrv1 { .host = "192.168.20.12"; .port = "80"; }
7)客户端测试
接下来进行vcl的功能拓展
一、 判断上边的配置是否命中缓存
(1)编辑test.vcl #vim /etc/varnish/test.vcl backend websrv1 { .host = "192.168.20.12"; .port = "80"; } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } (2)管理界面中重新编译 并使用 # varnish > vcl.load test3 test.vcl # varnish > vcl.use test3 (3)在varnish服务器测试 # curl -I http://172.16.13.2
命中
二、判断从哪个服务器命中缓存 ---使用变量server.ip
编辑test.vcl #vim /etc/varnish/test.vcl backend websrv1 { .host = "192.168.20.12"; .port = "80"; } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT" + server.ip; } else { set resp.http.X-Cache = "MISS"; } } 管理界面 重新编译并使用 # varnish > vcl.load test4 test.vcl # varnish > vcl.use test4 服务器测试 # curl -I http://172.16.13.2
三、 拒绝使用缓存 ---使用变量req.url
server2服务器再创建一个测试页面 #vim /var/www/html/test.html <h1>test!!!</h1> 编辑vcl配置文件增加vcl_recv子例程 #vim /etc/varnish/test.vcl sub vcl_recv { if (req.url ~ "test.html") { return(pass); } return(lookup); } varnish服务器测试 # curl -I http://172.16.13.2/test.html
全部miss,未命中
四、定义缓存时长
如果客户端请求的为图片文件,就缓存7200s, 如果客户端请求的为静态网页,就缓存1200s 编辑test.vcl 增加子例程vcl_fetch #vim /etc/varnish/test.vcl sub vcl_fetch { if (req.url ~ "\.(jpg|jpeg|gif|png)$") { set beresp.ttl = 7200s; } if (req.url ~ "\.(html|css|js)$") { set beresp.ttl = 1200; } } #serivice varnish reload 管理界面重新编辑 并使用 #varnish > vcl.load test6 test.vcl #varnish > vcl.use test6
五 使用PURGE修剪缓存
修剪缓存非常危险,所以我们必须要做好准备 在具体执行某清理工作时,需要事先确定如下问题: #(1)仅需要检验一个特定的缓存对象,还是多个? #(2)目的是释放内存空间,还是仅替换缓存的内容? #(3)是不是需要很长时间才能完成内容替换? #(4)这类操作是个日常工作,还是仅此一次的特殊需求? 移除单个缓存的实现 #vim /etc/varnish/test.vcl 增加内容如下 acl purgers { "127.0.0.1"; "172.16.0.0"/16; } sub vcl_recv { if (req.request == "PURGE") { if (!client.ip ~ purgers) { error 405 "Method not allowed"; } } if (req.url ~ "test.html") { return(pass); } return(lookup); } sub vcl_hit { if (req.request == "PURGE") { purge; error 200 "PURGE OK"; } } sub vcl_miss { if (req.request == "PURGE") { purge; error 404 "Not in cache"; } } sub vcl_pass { if (req.request == "PURGE") { error 502 "Purged on a passed object"; } } 管理界面重新编译vcl并使用 #varnish > vcl.load test8 vcl.test #varnish > vcl.use test8 测试 客户端在发起HTTP请求时,只需要为所请求的URL使用PURGE方法即可 使用 curl -I -X PURGE http://varniship/path/to/someurl
六、定义varnish服务器检测后端服务器健康状态
后端服务器为 192.168.12.12和 192.168.12.13 #vim /etc/varnish/test.vcl backend web1 { .host = "192.168.20.12"; .port = "80"; .probe = { .url = "/index.html"; .interval = 1s; .window = 5; .threshold = 2; } } backend web2 { .host = "192.168.20.13"; .port = "80"; .probe = { .url = "/index.html"; .interval = 1s; .window = 5; } .threshold = 2; } director webs random { { .backend = web1; .weight = 2; } { .backend = web2; .weight = 1; } } 同时在子例程 vcl_recv 中添加调用req.backend set req.backend = webs; 管理接口重新编译vcl 并好似用 # varnish > vcl.load test9 vcl.test # varnish > vcl.use test9
客户端测试
首先关闭192.168.20.12 服务器的httpd服务
启动192.168.20.12 httpd服务
七 将请求的静态网页发送至web1服务器
将请求的图片发送至web2服务器
编辑test.vcl # vim /etc/varnish/test.vcl 添加如下内容 sub vcl_recv { if (req.url ~ "\.(html|css|js)$") { set req.backend = web1; } else { set req.backend = web2; } #同时注释掉director所有内容
八 如何防盗链
搜的例子: if (req.http.referer ~ "http://.*") { if ( !(req.http.referer ~ "http://.*ixdba\.net" || req.http.referer ~ "http://.*google\.com" || req.http.referer ~ "http://.*yahoo\.cn"et || req.http.referer ~ "http://.*google\.cn" )) { set req.http.host = "www.ixdba.net"; set req.url = "/templets/default/images/logo.gif"; } return (lookup); }
varnish常用的工具
1 varnishstat 查看状态的命令工具 用法: -1 -l:列出所有参数 -f f1,f2 例如 varnishstat -f cache_hit,cache_miss 只查看这两项 # 需要关注的几个参数 cache hit cache miss client_req client_conn n_wrk n_wrk_create n_backend n_expired n_lru_moved s_hdrbytes s_bodybytes 2 varnishtop 实时显示日志中的信息 用法: -i tag : 仅显示指定的tag,如RxHeader -I regexp : 以模式匹配tag对应值; -C :正则表达式匹配时不区分字符大小写; 3 varnishlog #server varnishlog start 开启varnishlog #tail -f /var/log/varnish/varnish.log 4 varnishreplay 日志重放工具,用于实现缓存预热
几个重要调整的参数
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 # varnish> help # varnish> param.show 查看所有参数 几个重要的参数 thread_pool_add_delay 两个客户端创建线程池时的时间间隔 thread_pool_fail_delay 创建线程池失败后,第二次创建时的时间间隔 thread_pool_max 一个线程池中默认装载的最大的线程数 thread_poo_min 一个线程池中默认装载的最小的线程数,限定避免其过于不均衡,防止在繁忙中有的线程池不能少于这个值 thread_pool_purge_delay 多长时间清理一次线程, thread_pool_timeout 一个线程空闲多长时间 就清除掉 thread_pool_workspace 一个线程池 thread_pools 工作线程池的个数 thread_stats_rate 一批搜集多少个工作线程的状态信息 参数调整方法 # varnish> param.show thread_pools # varnish> param.set thread_pools 3 # varnish> param.show thread_pools
思考篇
缓存命中率低的原因
缓存空间太小 --------------增大内存,增大磁盘 不存在明显的热点数据------------(二八法则:80%的请求落在20%的数据上 )---可以不用做缓存了,或者将原数据全部做到缓存 源文件更新过于频繁 -----------建议不要使用缓存了 缓存服务器的可用性 ---------------做分布式
本文出自 “西风瘦猪” 博客,请务必保留此出处http://jungege.blog.51cto.com/4102814/1408107
强大的http加速器------varnish,布布扣,bubuko.com
原文地址:http://jungege.blog.51cto.com/4102814/1408107