Varnish:
varnish是一款轻量级的http cache和反向代理软件,类似于nginx,缓存功能非常强大,相比squid重量级的缓存服务,varnish 具有性能更高、速度更快、管理更加方便等诸多优点,很多大型的网站都开始尝试使用 varnish 来替换 squid,这些都促进 varnish 迅速发展起来。
挪威的最大的在线报纸 Verdens Gang(vg.no) 使用 3 台 Varnish 代替了原来的 12 台 Squid,性能比以前更好,这是 Varnish 最成功的应用案例。 //这个看看就行
varnish组成部分分为三部分:
1、Management:命令行、子进程管理、编译VCL并应用新配置,监控vanish,初始化varnish。
2、Child/cache: 命令行、缓存hash、日志数据统计、接收用户请求、工作线程、与后端主机的连接,缓存有效性验证清理。
3、VCL: 控制缓存机制,而不是控制varnish,调用C编译器,生成二进制程序,让子进程加载。
varnish存储缓存内容的方法:
1、file:自管理的文件系统,黑盒,只对当前进程有效,不支持持久机制;
2、malloc:使用内存分配函数malloc()库调用varnish启动时向内存申请指定大小的空间;
3、persisent:与file功能相同;仍处于测试期,基于文件的持久存储。
缓存:
把向服务器端请求到的资源缓存到本地,提供响应速率,并减少对后端服务器的压力,但并不是所有的数据都需要缓存,缓存的数据必须要有热点性,如果数据不存在热点性,那缓存也没什么意义,而且私有数据是不能缓存的。
衡量一个缓存的有效性:
缓存命中率:hit/(hit+miss)
文档命中率: 从文档个数进行衡量
字节命中率: 从内容的大小进行衡量
缓存的生命周期:
缓存的清理有两种情况
缓存项过期: 惰性清理
缓存空间用尽:LRU算法
一个缓存项的过期并不会真正从内存中清理,只是简单标记为失效,而不是把它删除,只有当缓存空间空间用尽时,才会真正的删除缓存项。
因为缓存都有生命周期,如果判断缓存是否有效,可以根据新鲜度检测及有效性再验正:revalidate。
新鲜度检测机制:给予过期日期,多久之后才消失
HTTP/1.0 Expires, 给予的是绝对时长,缺点是时间不同步会导致缓存总是失效
Expires:Thu, 04 Jun 2015 23:38:18 GMT
HTTP/1.1 Cache-Control: max-age 给予的是相对时长,接收到响应报文后开始算起
Cache-Control:max-age=600
有效性再验正:revalidate
如果原始内容未改变,则仅响应首部(不附带body部分),响应码304 (Not Modified)
如果原始内容发生改变,则正常响应,响应码200;
如果原始内容消失,则响应404,此时缓存中的cache object也应该被删除;
有效性在验证时的条件式请求首部:
If-Modified-Since: 基于请求内容的最近一次修改的时间戳作验正;(返回200,并响应新的内容)
If-Unmodified-Since: 基于请求内容的最近的一次是否发生改变 (返回304 not modified)
If-Match: 基于请求内容的匹配做验证
If-None-Match: 基于Etag的比较进行内容验证
一个完整的缓存处理请求:
接收请求-->解析请求(提取请求的URL及各种首部)-->根据key来查询缓存-->新鲜度检测-->有效性在验证-->创建响应报文-->发送响应-->记录日志
一、安装varnish
]# yum -y install varnish ]# rpm -ql varnish /etc/varnish /etc/varnish/default.vcl //VCL配置文件,管理缓存策略 /etc/varnish/varnish.params //varnish配置参数
编辑varnish配置参数文件:
]# vim /etc/varnish/varnish.params RELOAD_VCL=1 //重新编译VCL配置文件 VARNISH_VCL_CONF=/etc/varnish/default.vcl //VCL配置文件 # VARNISH_LISTEN_ADDRESS=192.168.1.5 //监听的IP地址 VARNISH_LISTEN_PORT=6080 //监听的端口,如果作为反向代理则需要改成80 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 //管理varnish程序的地址 VARNISH_ADMIN_LISTEN_PORT=6082 //管理varnish的端口 VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G" varnish_storage.bin 二进制文件 //缓存内容的存储 VARNISH_TTL=120 //默认缓存的有效期 DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300 //定义其他扩展选项,调优专用
请求报文的流程图:
vcl:
1、"域"专用的编程语言,类似于iptables的钩子函数,只要符合要求的都处理,不符合要求的跳转到下一个状态。
2、状态引擎:
vcl_recv:接收
vcl_hash:hash
vcl_hit: 命中
vcl_miss: 未命中
vcl_purge: 清缓存
vcl_pipe: 建立管道,直接送到后端主机
vcl_pass: 跳过,直接传送到pass
vcl_backend_fetch 后端取数据
vcl_backend_response
vcl_backend_error
vcl_synth: 同步
vcl_deliver:返回客户端
数据报文请求流向:
vcl_recv -->vcl_hash(对请求的内容做hash计算)-->分为四种情况
1、如果命中(vcl_hit )-->直接发送给客户端(vcl_deliver)或者vcl_pass,不请求缓存,直接传递给后端(vcl_backend_fetch)
2、如果未命中(vcl_miss)-->发送给vcl_pass,再由vcl_pass传递给后端取数据,或者直接传递给后端
3、如果请求的是purge,则直接清理缓存并同步vcl_synth
4、如果请求的内容未知,则vcl_pipe(管道)直接传递给后端主机,varnish只缓存静态文件
vcl_backend_fetch -->
1、后端主机处理完后发送响应报文给varnish,varnish判断是否可以缓存,然后响应给客户端
2、后端主机也处理不了,直接返回error给varnish,然后响应给客户端
VCL支持的语法:
vcl的语法:
1、//,#,/*...*/ :注释
2、sub $name: 定义子历程:
sub vcl_recv {
}
3、不支持循环,支持条件判断
if (CONDTION) {
} else {
}
4、有内建变量;
req.http resp.http
5、使用终止语句return,没有返回值
6、操作符:==,==,!=,~,&&,||
VCL的内建变量:
内建变量:
req.*: 请求,接收客户端的请求
req.http.*;请求报文各首部值
resp.*: 由varnish响应给client的http的响应报文;
resp.http:响应报文的首部
bereq.*: 由varnish向backend主机发出的http请求;
beresp.*:由后端主机发来的响应报文的首部;(在vcl_fetch和vcl_respone中实现)
obj.*: 存储在缓存空间中的缓存对象属性;只读;
client.*: 可用在所有的client side的sub routines中
server.*: varnish主机
storage.*: 存储类型
常用的内建变量:
bereq:varnish请求后端主机的报文
bereq.http.HEADERS: 由varnish发往backend server的请求报文的指定首部;
bereq.request:请求方法;
bereq.url: 请求的url
bereq.proto:请求的协议版本
bereq.backend:指明要调用的后端主机;
beresp 后端返回的响应报文
beresp.proto 协议版本
beresp.status:后端服务器的响应的状态码
beresp.reason:原因短语;
beresp.backend.ip: 获取后端服务器的IP
beresp.backend.name:获取后端服务器的名称
beresp.http.HEADER: 从backend server响应的报文的首部;
beresp.ttl:后端服务器响应的内容的余下的生存时长;
obj:对象
obj.ttl: 对象的ttl值;缓存时长
obj.hits:此对象从缓存中命中的次数;
server: varnish主机
server.ip 获取varnish的ip
server.hostname 获取varnish的主机名
server.port 获取varnish的端口
req:接收客户端的请求
req.method: 请求方法
req.url: 请求的url
自定义变量:
set beresp.ttl = varlue
set resp.http.X-cache = value
编辑VCL配置文件:
backend webser1 { //设置后端主机 .host = "172.18.250.76"; .port = "80"; }
示例:设置响应首部,查看缓存是否命中:
sub vcl_deliver { if(obj.hits>0) { set resp.http.X-cache = "HIT" + “ ” + server.ip; }else{ set resp.http.X-cache = "MISS" + “ ” + server.ip; } }
第二次请求就为HIT:
示例:强制对某资源进行请求,不检查缓存:
sub vcl_recv { if(req.url ~ "^/index.html"){ return(pass) } }
对特定类型的资源,例如公开的图片等,取消其私有的cookie标识,并强行设定其可以varnish缓存的时长:
if (beresp.http.cache-control !~ "s-maxage") { if (bereq.url ~ "(?i).jpg$") { //(?i)不区分大小写 set beresp.ttl = 60s; unset beresp.http.Set-Cookie; } }
示例:清理缓存缓存
sub vcl_recv { if(req.method == "PURGE"){ if(client.ip !~ purges){ return(synth(405)); } return(purge); } } ]# curl -X PURGE http://172.18.250.77 <!DOCTYPE html> <html> <head> <title>200 purges</title>
二、varnish可以作为负载均衡:
]# vim /etc/varnish/default.vcl import directors; backend default1 { .host = "172.18.250.76"; .port = "80"; } backend default2 { .host = "172.18.250.78"; .port = "80"; } sub vcl_init { new mycluster = directors.round_robin(); mycluster.add_backend(default1); mycluster.add_backend(default2); } vcl_recv { set req.backend_hint = mycluster.backend(); }
三、varnish也可以对后端主机进行健康状态检测:
backend default { .host = "172.16.100.68"; .port = "80"; .probe = { .url = "/test1.html"; //测试页 .interval = 1s; //扫描时间 .window = 8; //最近探测的次数 .threshold = 5; //探测有5次返回正常才算健康 .timeout = 2s; //后端主机超时时长 } }
四、varnish也提供了很多命令行工具:
]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 200 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,3.10.0-229.el7.x86_64,x86_64,-sfile,-smalloc,-hcritbit varnish-4.0.3 revision b8c4a34 Type ‘help‘ for command list. Type ‘quit‘ to close CLI session.
]# varnishstat