Varnish基础原理及简单配置
- Varnish简介:
Varnish是一填款高性能的开源HTTP加速器,同时作为http反向缓存
补充资料:
http://book.varnish-software.com/4.0/
特点
- Varnis可以使用内存也可以使用硬盘进行数据缓存
- 支持虚拟内存的使用
- 有精确的时间管理机制
- 状态引擎架构:通过特定的配置语言设计不同的语句
- 以二叉堆格式管理数据
优势:
- varnish访问速度快,因为采用了“Visual Page Cache”技术,在读取数据时直接从内存中读取
- varnish支持更多的并发连接,因为varnish的TCP连接比squid快
- varnish通过管理端口,使用正则表达式批量的清除部分缓存
劣势
- 进程一旦crash或重启,缓存的数据将从内存中完全释放,导致后端服务器压力过大,重新启动的热身时间,需要耗时数小时不等
- 在多台varnish实现负载均衡时,每次请求都会落到不同的varnish服务器中,造成url请求可能会穿透到后端
解决方案:
A:在varnish的后端添加squid/nginx代理,这样防止了当varnish缓存被清空时,瞬间大量的请求发往web服务器
B:在负载均衡上做hash request_url,让单个url请求固定请求到一台varnish服务器上
- varnish组成:
Management进程,用来管理进程,对child进程进行管理,同时对vcl配置进行编译
child进程,子进程,生成线程池,负责处理用户请求
阶段:
- req:处理客户端发送的请求时使用
- bereq:处理varnish向后端服务器发送的请求时使用
- beresp:处理后端服务器响应时使用,用于varnish未缓存前
- resp:处理返回给客户端的响应时使用
- obj:处理存储在内存中的对象时使用
varnish工作流程图:
- 客户端发送的请求对象
阶段对象 说明
req 整个HTTP请求数据结构
req.backend_hint 指定请求的后端节点
req.http 对应请求HTTP的header
req.can_gzip 客户端是否接受GZIP传输编码
req.hash_always_miss 是否强制不命中高速缓存
req.hash_ignore_busy 忽略缓存中忙碌的对象,多台缓存时可以避免死锁
req.method 请求类型(如GET,POST)
req.restarts 重新启动次数,默认最大值是4
req.ttl 缓存剩余时间
req.url 请求的url
req.xid 唯一ID
- 发送到后端的请求对象
bereq 整个后端请求后数据结构
bereq.backend 所请求后端节点配置
bereq.between_bytes_timeout 从后端每接收一个字节之间的等待时间(秒)
bereq.connect_timeout 连接后端等待时间(秒),最大等待时间
bereq.first_byte_timeout 等待后端第一个字节时间(秒),最大等待时间
bereq.http 对应发送到后端HTTP的header信息
bereq.method 发送到后端的请求类型
bereq.uncacheable 无缓存这个请求
bereq.url 发送到后端请求的URL
bereq.xid 请求唯一ID
- 后端响应请求对象
beresp 整个后端响应HTTP数据结构
beresp.backend.ip 后端响应的IP
beresp.backend.name 响应后端配置节点的name
beresp.do_gunzip 默认为false,缓存前解压该对象
beresp.do_gzip 默认为false,缓存前压缩该对象
beresp.grace 设置当前对象缓存过期后可额外宽限时间
beresp.http 对应的HTTP请求header
beresp.keep 对象缓存后带保持时间
beresp.reason 由服务器返回的HTTP状态信息
beresp.status 由服务器返回的状态码
beresp.storage_hint 指定保存的特定存储器
beresp.ttl 该对象缓存的剩余时间,指定统一缓存剩余时间
beresp.uncacheable 继承bereq.uncacheable,是否不缓存
- 高速缓存对象,缓存后端响应请求内容
obj.grace 该对象额外宽限时间
obj.hits 缓存命中次数
obj.http 对应HTTP的header
obj.reason 服务器返回的HTTP状态信息
obj.status 服务器返回的状态码
obj.ttl 该对象缓存剩余时间秒
obj.uncacheable 不缓存对象
- 返回给客户端的响应对象
resp 整个响应HTTP数据结构
resp.http 对应HTTP的hearder
resp.proto 编辑响应的HTTP协议版本
resp.reason 将要返回的HTTP状态信息
resp.status 将要返回的HTTP状态码
- 运算符:
- =:赋值运算
- ==:相等比较
- ~ :匹配,可以使用正则表达式,或访问控制列表
- !~:不匹配,可以使用正则表达式,或访问控制列表
- ! :非
- &&:逻辑与
- ||:逻辑或
- 功能语句与对象
一般功能语句都用于匹配对象,就是对某个对象实现什么操作
- ban():清除指定对象缓存
- ban_url(regex):可以清除被此处匹配到的缓存
- call():调用子程序
- hash_data():生成hash键值,只能在vck_hash子程序中使用
- new():创建一个vcl对象,只能在vcl_init子程序中使用
- return():结束当前子程序并执行下一步动作
- rollback():恢复http头到原来的状态,现在使用std.rollback()代替
- synthetic():合成器,用于自定义一个响应内容,只能在vcl_synth和vcl_backend_error子程序中使用
- regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite
- regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;
-
return的常用动作
语法:return (action)
- abandon:放弃处理,并生成一个错误
- deliver:交付至后端处理
- fetch:从后端取出响应对象
- hash:哈希缓存处理
- lookup:从缓存中查找应答数据并返回,如果查找不到,则调用pass函数,从后端服务器调用数据
- ok:继续执行
- pass:绕过缓存,直接向后端服务器调用数据
- pipe: 建立客户端和后端服务器之间的直接连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到断开连接
- purge:清除缓存对象,构建响应
- restart:重新开始
- retry: 重试后端处理
- synth 合成响应报文,响应客户端
varnish中内置子程序:
- 子进程也叫状态引擎,每一个状态引擎均有自己限定的返回动作return,不同的动作将调用对应下一个状态引擎。
- 我们可以把一个请求分为多个阶段,每个阶段都会调用不同的状态引擎去操作,这样,我们只编写出相应的状态引擎,就可认控制每个请求阶段
- varnish内置子程序均有自己限定的返回动作return,不同的动作将调用对应下一个子程序
每个子程序都需要通过关键字sub进行定义
-
vcl_recv子程序
开始处理请求,通过return(动作);选择varnish处理模式,默认进入hash缓存模式(即return(hash);),缓存时间为配置default_ttl(默认为120秒)过期保持时间default_grace(过期容忍时间,默认为10秒)。该子程序一般用于模式选择,对象缓存及信息修改,后端节点修改,终止请求等操作
返回值:synth,pass,pipe,hash,pruge
-
vcl_pipe子程序
pipe模式处理,该模式主要用于直接取后端响应内容返回客户端,可定义响应内容返回客户端。该子程序一般用于需要及时且不作处理的后端信息,取出后端响应内容后直接交付到客户端不进入vcl_deliver子程序处理
返回值:synth,pipe
-
vcl_pass子程序
pass模式处理,该模式类似hash缓存模式,仅不做缓存处理
返回值:synth,fetch:继续pass模式,进入后端vcl_backend_fetch子程序,默认返回值
-
vcl_hit子程序
hash缓存模式时存在hash缓存时调用,用于缓存处理,可放弃或修改缓存
返回值:restart,deliver默认返回值,synth
-
vcl_miss子程序
hash缓存模式时不存在hash缓存时调用,用于判断性的选择进入后端取响应内容,可以修改为pass模式
返回值:restart重启请求,synth,pass,fetch:正常取后端内容再缓存,进入vcl_backend_fetch子程序,默认返回值
-
vcl_hash
hash缓存模式,生成hash值作为缓存查找键名提取缓存内容,主要用于缓存hash键值处理,可使用hash_data(string)指定键值组成结构,可在同一页面通过IP或Cookie生成不同的缓存键值
返回值:lookup:查找缓存对象,存在缓存进入vcl_hit子程序,不存在缓存进入vcl_miss子程序,当使用了purge清理模式时会进入vcl_purge子程序,默认返回值
-
acl_purge子程序
清理模式,当查找到对应的缓存时清除并调用,用于请求方法清除缓存,并报告
返回值:synth,restart
-
vcl_deliver子程序
客户端交付子程序,在vcl_backend_response子程序后调用(非pipe模式),或vcl_hit子程序后调用,可用于追加响应头信息,cookie等内容
返回值:deliver,restart
-
vcl_backend_fetch子程序
发送后端请求之前调用,可用于改变请求地址或其它信息,或放弃请求
返回值:fetch:正常发送请求到后端取出响应内容,进入vcl_backend_response子程序,默认返回值,abandon
-
vcl_backend_redponse子程序
后端响应后调用,可用于修改缓存时间及缓存相关信息
返回值:deliver,abandon,retry:重试后端请求,重试计数器加1,当超过配置中max_retries值时会报错并进入vcl_backend_error子程序
-
vcl_backend_error子程序
后端处理失败调用,异常页面展示效果处理,可自定义错误响应内容,或修改beresp.status与beresp.http.Location重定向等
返回值:deliver,retry
-
vcl_synth子程序
自定义响应内容,可以通过synthetic()和返回值synth调用,这里可以自定义异常显示内容,也可以修改resp.status与resp.http.Location重定向
返回值:deliver,restart
-
vcl_init子程序
加载vcl时最先调用,用于初始化VMODs,该子程序不参与请求处理,仅在vcl加载时调用一次
返回值:ok
-
vcl_fini子程序
卸载当前vcl配置时调用,用于清理VMODs,该子程序不参与请求处理,仅在vcl正常丢弃后调用
返回值:ok
后端服务器定义:
属性 说明
.host= "IP"; 要转向主机(即后端主机)的IP或域名,必填键值对
.port = "80"; 主机连接端口号或协议名(HTTP等),默认80
.connect_timeout = 0.5s; 连接后端主机的超时时长
.first_byte_timeout = 2s; 等待从后端返回的第一个字节时间
.between_bytes_timeout = 2s; 每接收一个字节之间等待时间
.probe = probe_name 监控后端主机的状态,指定外部监控name或者内部直接添加
.max_connections = 1000; 设置最大并发连接数,超过这个数后连接就会失败
监视器定义
.url = "/"; 指定监控入口地址,默认为“/”
.request = ""; 指定监控请求入口地址,比.url优先级高
.timeout = ""; 超时时长
.window = ""; 基于最近的多少次检查来判断其健康状态,默认为8
.threshold = ""; 最近.window中定义的这么次检查中至少有.threshold定义的次数是成功的,默认是3
.interval = ""; 检测频度,默认为5秒
.initial = -1 window中有几次是良好启用此节点
.expected_reponse = ""; 期望的响应码,默认为200
- 检测实例:
probe check {
.url = "/";
.timeout = 2s;
.interval = 2s; //这里又引入了新的问题,虽然会去自动检测后端主机的健康性,但是后端主机会记录日志的,如果设定的时间过短,会增大后端服务器的磁盘压力,过长,则会使用户感觉不好,设一个稳点的值
.window = 8;
.threshold = 6;
}
backend websrv {
.host = "172.16.252.113";
.port = "80";
.max_connections = 500;
.probe = check;
}
>backend.list
200
Backend name Refs Admin Probe
websrv(172.16.252.113,,80) 4 probe Sick 5/8 //检测出来的效果sick生病了
default(127.0.0.1,,8080) 4 probe Healthy (no probe)
backend.list
200
Backend name Refs Admin Probe
websrv(172.16.252.113,,80) 4 probe Sick 4/8
default(127.0.0.1,,8080) 4 probe Healthy (no probe)
backend.list
200
PURGE和BAN操作,来清理特定的缓存,也可以在命令行中执行
acl purgers {
"127.0.0.1";
"192.168.0.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.0...
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return (synth(405, "Purging not allowed for " + client.ip));
}
return (purge);
}
}
sub vcl_purge {
return (synth(200,"Purged,now!"));
# set req.method = "GET";
# return (restart);
}
if (req.method == "BAN") {
if (!client.ip ~ purgers) {
return (synth(405,"Banning not allowd for" + client.ip));
}
ban(" req.http.host == " + req.http.host + " && req.url == " + req.url);
//运算符边上必须有空格,要不然会实现不了功能的
return (synth(200,"Ban added."));
}
操作:
~]# varnish -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test1 default.vcl
vcl.use test1
也可在此操作清除缓存:
ban req.url ~ .js$ //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便
客户端操作:
~]# crul -I http://172.16.254.35
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 27 Jun 2017 09:27:38 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 27 Jun 2017 06:21:47 GMT
ETag: "5951f97b-11"
X-Varnish: 3964978
Age: 0
Via: 1.1 varnish-v4
X-Cache: Miss via172.16.254.35 //没有命中
Connection: keep-alive
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
进行PURGE操作:
~]# curl -X PURGE http://172.16.254.35/index.html
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
~]# curl -I http://172.16.254.35/index.html
...
X-Cache: Miss via172.16.254.35 //不能命中缓存
...
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
进行BAN操作:
~]# curl -X BAN http://172.16.254.35/index.html
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
~]# curl -I http://172.16.254.35/index.html
...
X-Cache: Miss via172.16.254.35 //不能命中缓存
...
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
- 实例:在缓存中,强制对某类资源的请求不检查缓存:
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") { //(?i)不区分字符大小写
return(pass);
}
}
- 实例:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长;定义在vcl_backend_response中
if (beresp.http.cache-control !~ "s-maxage") { //如果后端服务器没有给缓存时长
if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") { //同时匹配以.jpg...结尾的文件
unset beresp.http.Set-Cookie; //说明:默认情况下,varnish不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,varnish将忽略缓存,直接将请求递送至后端服务器上
set beresp.ttl = 3600s; //设置后端响应首部的生存时长为1h
}
}
- 实例:将真实的客户IP地址转移至后端服务器上,以便日志记录
if (req.restarts == 0) {
if (req.http.X-Fowarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
- 最后的一个整体笔记:
import directors; //负载均衡集群需要directors模块支持,import directors
acl purgers { //对缓存资源进行控制
"127.0.0.1";
"172.16.0.0"/16;
}
probe check { //对后端服务器的状态检测
.url = "/";
.timeout = 2s;
.interval = 10s;
.window = 8;
.threshold = 6;
}
backend websrv { //定义后端主机的属性
.host = "172.16.252.113";
.port = "80";
.max_connections = 500;
.port = "80";
.max_connections = 500;
.probe = check; //执行健康状态检测
}
backend websrv2 {
.host = "172.16.250.84";
.port = "80";
.probe = check;
}
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_init { //初始化子程序创建后端主机组,即directors
new WEBGROUP = directors.round_robin(); //使用new关键字创建director对象,使用round_robin算法
WEBGROUP.add_backend(websrv);
WEBGROUP.add_backend(websrv2);
WEBGROUP.add_backend(websrv);
WEBGROUP.add_backend(websrv2);
}
sub vcl_recv { //接受请求子程序
set req.backend_hint = WEBGROUP.backend(); //调用后端主机组
if (req.url ~ "(?i)\.(JPG|PNG|GIF)") { //对几种图片不进行缓存查找
return(pass);
}
if (req.restarts == 0) { //IP地址转移
if (req.http.X-Forwarded-For) {
set req.http.x-forwarded-for = req.http.x-forwarded-for + "," + client.ip;
} else {
set req.http.x-forwarded-for = client.ip;
}
}
if (req.method == "PURGE") { //对某个缓存对象进行清理操作
if (!client.ip ~ purgers) {
return (synth(405,"Purging not allowed for" + client.ip));
}
return (purge); //去往purge子程序操作
}
if (req.method == "BAN") { //清理某一类缓存对象
if (!client.ip ~ purgers) {
return (synth(405,"Banning not allowd for" + client.ip));
}
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);//清除host+url的对象
return (synth(200,"Ban added."));
}
# if (req.url ~ "(?i)\.php$") { //以.php请求至后端
# set req.backend_hint = websrv;
# } else {
# set req.backend_hint = default;
# }
}
sub vcl_purge { //purge子程序
return (synth(200,"Purged"));//合成信息,并返回值
# set req.method = "GET";//将请求方法设置成GET
# return (restart);//在发还给客户端,让客户端重新来取
}
sub vcl_backend_response {
# Happens after we have read the response headers from the backend.
#
# Here you clean the response headers, removing silly Set-Cookie headers
# and other mistakes your backend does.
}
sub vcl_deliver { //发送给客户的数据报文
if (obj.hits>0) { //测试用,如果 有缓存,就把X-Cache首部信息发给客户端
set resp.http.X-Cache = "Hit via" + server.ip;
} else {
set resp.http.X-Cache = "Miss via" + server.ip;
}
}
varnish日志区域:
1、varnishstat - Varnish Cache statistics
-1 //显示一次
-1 -f FILED_NAME
-l:可用于-f选项指定的字段名称列表;
MAIN.cache_hit
MAIN.cache_miss
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
# varnishstat -l -f MAIN -f MEMPOOL
2、varnishtop - Varnish log entry ranking
-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;
-I <[taglist:]regex>
-x taglist:排除列表
-X <[taglist:]regex>
3、varnishlog - Display Varnish logs
4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format
systemctl start varnishncsa.service //开启日志功能服务
Varnish基础原理及简单配置
- Varnish简介:
Varnish是一填款高性能的开源HTTP加速器,同时作为http反向缓存
补充资料:
http://book.varnish-software.com/4.0/
特点
- Varnis可以使用内存也可以使用硬盘进行数据缓存
- 支持虚拟内存的使用
- 有精确的时间管理机制
- 状态引擎架构:通过特定的配置语言设计不同的语句
- 以二叉堆格式管理数据
优势:
- varnish访问速度快,因为采用了“Visual Page Cache”技术,在读取数据时直接从内存中读取
- varnish支持更多的并发连接,因为varnish的TCP连接比squid快
- varnish通过管理端口,使用正则表达式批量的清除部分缓存
劣势
- 进程一旦crash或重启,缓存的数据将从内存中完全释放,导致后端服务器压力过大,重新启动的热身时间,需要耗时数小时不等
- 在多台varnish实现负载均衡时,每次请求都会落到不同的varnish服务器中,造成url请求可能会穿透到后端
解决方案:
A:在varnish的后端添加squid/nginx代理,这样防止了当varnish缓存被清空时,瞬间大量的请求发往web服务器
B:在负载均衡上做hash request_url,让单个url请求固定请求到一台varnish服务器上
- varnish组成:
Management进程,用来管理进程,对child进程进行管理,同时对vcl配置进行编译
child进程,子进程,生成线程池,负责处理用户请求
阶段:
- req:处理客户端发送的请求时使用
- bereq:处理varnish向后端服务器发送的请求时使用
- beresp:处理后端服务器响应时使用,用于varnish未缓存前
- resp:处理返回给客户端的响应时使用
- obj:处理存储在内存中的对象时使用
varnish工作流程图:
- 客户端发送的请求对象
阶段对象 说明
req 整个HTTP请求数据结构
req.backend_hint 指定请求的后端节点
req.http 对应请求HTTP的header
req.can_gzip 客户端是否接受GZIP传输编码
req.hash_always_miss 是否强制不命中高速缓存
req.hash_ignore_busy 忽略缓存中忙碌的对象,多台缓存时可以避免死锁
req.method 请求类型(如GET,POST)
req.restarts 重新启动次数,默认最大值是4
req.ttl 缓存剩余时间
req.url 请求的url
req.xid 唯一ID
- 发送到后端的请求对象
bereq 整个后端请求后数据结构
bereq.backend 所请求后端节点配置
bereq.between_bytes_timeout 从后端每接收一个字节之间的等待时间(秒)
bereq.connect_timeout 连接后端等待时间(秒),最大等待时间
bereq.first_byte_timeout 等待后端第一个字节时间(秒),最大等待时间
bereq.http 对应发送到后端HTTP的header信息
bereq.method 发送到后端的请求类型
bereq.uncacheable 无缓存这个请求
bereq.url 发送到后端请求的URL
bereq.xid 请求唯一ID
- 后端响应请求对象
beresp 整个后端响应HTTP数据结构
beresp.backend.ip 后端响应的IP
beresp.backend.name 响应后端配置节点的name
beresp.do_gunzip 默认为false,缓存前解压该对象
beresp.do_gzip 默认为false,缓存前压缩该对象
beresp.grace 设置当前对象缓存过期后可额外宽限时间
beresp.http 对应的HTTP请求header
beresp.keep 对象缓存后带保持时间
beresp.reason 由服务器返回的HTTP状态信息
beresp.status 由服务器返回的状态码
beresp.storage_hint 指定保存的特定存储器
beresp.ttl 该对象缓存的剩余时间,指定统一缓存剩余时间
beresp.uncacheable 继承bereq.uncacheable,是否不缓存
- 高速缓存对象,缓存后端响应请求内容
obj.grace 该对象额外宽限时间
obj.hits 缓存命中次数
obj.http 对应HTTP的header
obj.reason 服务器返回的HTTP状态信息
obj.status 服务器返回的状态码
obj.ttl 该对象缓存剩余时间秒
obj.uncacheable 不缓存对象
- 返回给客户端的响应对象
resp 整个响应HTTP数据结构
resp.http 对应HTTP的hearder
resp.proto 编辑响应的HTTP协议版本
resp.reason 将要返回的HTTP状态信息
resp.status 将要返回的HTTP状态码
- 运算符:
- =:赋值运算
- ==:相等比较
- ~ :匹配,可以使用正则表达式,或访问控制列表
- !~:不匹配,可以使用正则表达式,或访问控制列表
- ! :非
- &&:逻辑与
- ||:逻辑或
- 功能语句与对象
一般功能语句都用于匹配对象,就是对某个对象实现什么操作
- ban():清除指定对象缓存
- ban_url(regex):可以清除被此处匹配到的缓存
- call():调用子程序
- hash_data():生成hash键值,只能在vck_hash子程序中使用
- new():创建一个vcl对象,只能在vcl_init子程序中使用
- return():结束当前子程序并执行下一步动作
- rollback():恢复http头到原来的状态,现在使用std.rollback()代替
- synthetic():合成器,用于自定义一个响应内容,只能在vcl_synth和vcl_backend_error子程序中使用
- regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite
- regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;
-
return的常用动作
语法:return (action)
- abandon:放弃处理,并生成一个错误
- deliver:交付至后端处理
- fetch:从后端取出响应对象
- hash:哈希缓存处理
- lookup:从缓存中查找应答数据并返回,如果查找不到,则调用pass函数,从后端服务器调用数据
- ok:继续执行
- pass:绕过缓存,直接向后端服务器调用数据
- pipe: 建立客户端和后端服务器之间的直接连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到断开连接
- purge:清除缓存对象,构建响应
- restart:重新开始
- retry: 重试后端处理
- synth 合成响应报文,响应客户端
varnish中内置子程序:
- 子进程也叫状态引擎,每一个状态引擎均有自己限定的返回动作return,不同的动作将调用对应下一个状态引擎。
- 我们可以把一个请求分为多个阶段,每个阶段都会调用不同的状态引擎去操作,这样,我们只编写出相应的状态引擎,就可认控制每个请求阶段
- varnish内置子程序均有自己限定的返回动作return,不同的动作将调用对应下一个子程序
每个子程序都需要通过关键字sub进行定义
-
vcl_recv子程序
开始处理请求,通过return(动作);选择varnish处理模式,默认进入hash缓存模式(即return(hash);),缓存时间为配置default_ttl(默认为120秒)过期保持时间default_grace(过期容忍时间,默认为10秒)。该子程序一般用于模式选择,对象缓存及信息修改,后端节点修改,终止请求等操作
返回值:synth,pass,pipe,hash,pruge
-
vcl_pipe子程序
pipe模式处理,该模式主要用于直接取后端响应内容返回客户端,可定义响应内容返回客户端。该子程序一般用于需要及时且不作处理的后端信息,取出后端响应内容后直接交付到客户端不进入vcl_deliver子程序处理
返回值:synth,pipe
-
vcl_pass子程序
pass模式处理,该模式类似hash缓存模式,仅不做缓存处理
返回值:synth,fetch:继续pass模式,进入后端vcl_backend_fetch子程序,默认返回值
-
vcl_hit子程序
hash缓存模式时存在hash缓存时调用,用于缓存处理,可放弃或修改缓存
返回值:restart,deliver默认返回值,synth
-
vcl_miss子程序
hash缓存模式时不存在hash缓存时调用,用于判断性的选择进入后端取响应内容,可以修改为pass模式
返回值:restart重启请求,synth,pass,fetch:正常取后端内容再缓存,进入vcl_backend_fetch子程序,默认返回值
-
vcl_hash
hash缓存模式,生成hash值作为缓存查找键名提取缓存内容,主要用于缓存hash键值处理,可使用hash_data(string)指定键值组成结构,可在同一页面通过IP或Cookie生成不同的缓存键值
返回值:lookup:查找缓存对象,存在缓存进入vcl_hit子程序,不存在缓存进入vcl_miss子程序,当使用了purge清理模式时会进入vcl_purge子程序,默认返回值
-
acl_purge子程序
清理模式,当查找到对应的缓存时清除并调用,用于请求方法清除缓存,并报告
返回值:synth,restart
-
vcl_deliver子程序
客户端交付子程序,在vcl_backend_response子程序后调用(非pipe模式),或vcl_hit子程序后调用,可用于追加响应头信息,cookie等内容
返回值:deliver,restart
-
vcl_backend_fetch子程序
发送后端请求之前调用,可用于改变请求地址或其它信息,或放弃请求
返回值:fetch:正常发送请求到后端取出响应内容,进入vcl_backend_response子程序,默认返回值,abandon
-
vcl_backend_redponse子程序
后端响应后调用,可用于修改缓存时间及缓存相关信息
返回值:deliver,abandon,retry:重试后端请求,重试计数器加1,当超过配置中max_retries值时会报错并进入vcl_backend_error子程序
-
vcl_backend_error子程序
后端处理失败调用,异常页面展示效果处理,可自定义错误响应内容,或修改beresp.status与beresp.http.Location重定向等
返回值:deliver,retry
-
vcl_synth子程序
自定义响应内容,可以通过synthetic()和返回值synth调用,这里可以自定义异常显示内容,也可以修改resp.status与resp.http.Location重定向
返回值:deliver,restart
-
vcl_init子程序
加载vcl时最先调用,用于初始化VMODs,该子程序不参与请求处理,仅在vcl加载时调用一次
返回值:ok
-
vcl_fini子程序
卸载当前vcl配置时调用,用于清理VMODs,该子程序不参与请求处理,仅在vcl正常丢弃后调用
返回值:ok
后端服务器定义:
属性 说明
.host= "IP"; 要转向主机(即后端主机)的IP或域名,必填键值对
.port = "80"; 主机连接端口号或协议名(HTTP等),默认80
.connect_timeout = 0.5s; 连接后端主机的超时时长
.first_byte_timeout = 2s; 等待从后端返回的第一个字节时间
.between_bytes_timeout = 2s; 每接收一个字节之间等待时间
.probe = probe_name 监控后端主机的状态,指定外部监控name或者内部直接添加
.max_connections = 1000; 设置最大并发连接数,超过这个数后连接就会失败
监视器定义
.url = "/"; 指定监控入口地址,默认为“/”
.request = ""; 指定监控请求入口地址,比.url优先级高
.timeout = ""; 超时时长
.window = ""; 基于最近的多少次检查来判断其健康状态,默认为8
.threshold = ""; 最近.window中定义的这么次检查中至少有.threshold定义的次数是成功的,默认是3
.interval = ""; 检测频度,默认为5秒
.initial = -1 window中有几次是良好启用此节点
.expected_reponse = ""; 期望的响应码,默认为200
- 检测实例:
probe check {
.url = "/";
.timeout = 2s;
.interval = 2s; //这里又引入了新的问题,虽然会去自动检测后端主机的健康性,但是后端主机会记录日志的,如果设定的时间过短,会增大后端服务器的磁盘压力,过长,则会使用户感觉不好,设一个稳点的值
.window = 8;
.threshold = 6;
}
backend websrv {
.host = "172.16.252.113";
.port = "80";
.max_connections = 500;
.probe = check;
}
>backend.list
200
Backend name Refs Admin Probe
websrv(172.16.252.113,,80) 4 probe Sick 5/8 //检测出来的效果sick生病了
default(127.0.0.1,,8080) 4 probe Healthy (no probe)
backend.list
200
Backend name Refs Admin Probe
websrv(172.16.252.113,,80) 4 probe Sick 4/8
default(127.0.0.1,,8080) 4 probe Healthy (no probe)
backend.list
200
PURGE和BAN操作,来清理特定的缓存,也可以在命令行中执行
acl purgers {
"127.0.0.1";
"192.168.0.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.0...
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return (synth(405, "Purging not allowed for " + client.ip));
}
return (purge);
}
}
sub vcl_purge {
return (synth(200,"Purged,now!"));
# set req.method = "GET";
# return (restart);
}
if (req.method == "BAN") {
if (!client.ip ~ purgers) {
return (synth(405,"Banning not allowd for" + client.ip));
}
ban(" req.http.host == " + req.http.host + " && req.url == " + req.url);
//运算符边上必须有空格,要不然会实现不了功能的
return (synth(200,"Ban added."));
}
操作:
~]# varnish -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load test1 default.vcl
vcl.use test1
也可在此操作清除缓存:
ban req.url ~ .js$ //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便
客户端操作:
~]# crul -I http://172.16.254.35
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 27 Jun 2017 09:27:38 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 27 Jun 2017 06:21:47 GMT
ETag: "5951f97b-11"
X-Varnish: 3964978
Age: 0
Via: 1.1 varnish-v4
X-Cache: Miss via172.16.254.35 //没有命中
Connection: keep-alive
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
进行PURGE操作:
~]# curl -X PURGE http://172.16.254.35/index.html
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
~]# curl -I http://172.16.254.35/index.html
...
X-Cache: Miss via172.16.254.35 //不能命中缓存
...
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
进行BAN操作:
~]# curl -X BAN http://172.16.254.35/index.html
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
~]# curl -I http://172.16.254.35/index.html
...
X-Cache: Miss via172.16.254.35 //不能命中缓存
...
~]# curl -I http://172.16.254.35/index.html
....
X-Cache: Hit via172.16.254.35 //命中
...
- 实例:在缓存中,强制对某类资源的请求不检查缓存:
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") { //(?i)不区分字符大小写
return(pass);
}
}
- 实例:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长;定义在vcl_backend_response中
if (beresp.http.cache-control !~ "s-maxage") { //如果后端服务器没有给缓存时长
if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") { //同时匹配以.jpg...结尾的文件
unset beresp.http.Set-Cookie; //说明:默认情况下,varnish不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,varnish将忽略缓存,直接将请求递送至后端服务器上
set beresp.ttl = 3600s; //设置后端响应首部的生存时长为1h
}
}
- 实例:将真实的客户IP地址转移至后端服务器上,以便日志记录
if (req.restarts == 0) {
if (req.http.X-Fowarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
- 最后的一个整体笔记:
import directors; //负载均衡集群需要directors模块支持,import directors
acl purgers { //对缓存资源进行控制
"127.0.0.1";
"172.16.0.0"/16;
}
probe check { //对后端服务器的状态检测
.url = "/";
.timeout = 2s;
.interval = 10s;
.window = 8;
.threshold = 6;
}
backend websrv { //定义后端主机的属性
.host = "172.16.252.113";
.port = "80";
.max_connections = 500;
.port = "80";
.max_connections = 500;
.probe = check; //执行健康状态检测
}
backend websrv2 {
.host = "172.16.250.84";
.port = "80";
.probe = check;
}
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_init { //初始化子程序创建后端主机组,即directors
new WEBGROUP = directors.round_robin(); //使用new关键字创建director对象,使用round_robin算法
WEBGROUP.add_backend(websrv);
WEBGROUP.add_backend(websrv2);
WEBGROUP.add_backend(websrv);
WEBGROUP.add_backend(websrv2);
}
sub vcl_recv { //接受请求子程序
set req.backend_hint = WEBGROUP.backend(); //调用后端主机组
if (req.url ~ "(?i)\.(JPG|PNG|GIF)") { //对几种图片不进行缓存查找
return(pass);
}
if (req.restarts == 0) { //IP地址转移
if (req.http.X-Forwarded-For) {
set req.http.x-forwarded-for = req.http.x-forwarded-for + "," + client.ip;
} else {
set req.http.x-forwarded-for = client.ip;
}
}
if (req.method == "PURGE") { //对某个缓存对象进行清理操作
if (!client.ip ~ purgers) {
return (synth(405,"Purging not allowed for" + client.ip));
}
return (purge); //去往purge子程序操作
}
if (req.method == "BAN") { //清理某一类缓存对象
if (!client.ip ~ purgers) {
return (synth(405,"Banning not allowd for" + client.ip));
}
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);//清除host+url的对象
return (synth(200,"Ban added."));
}
# if (req.url ~ "(?i)\.php$") { //以.php请求至后端
# set req.backend_hint = websrv;
# } else {
# set req.backend_hint = default;
# }
}
sub vcl_purge { //purge子程序
return (synth(200,"Purged"));//合成信息,并返回值
# set req.method = "GET";//将请求方法设置成GET
# return (restart);//在发还给客户端,让客户端重新来取
}
sub vcl_backend_response {
# Happens after we have read the response headers from the backend.
#
# Here you clean the response headers, removing silly Set-Cookie headers
# and other mistakes your backend does.
}
sub vcl_deliver { //发送给客户的数据报文
if (obj.hits>0) { //测试用,如果 有缓存,就把X-Cache首部信息发给客户端
set resp.http.X-Cache = "Hit via" + server.ip;
} else {
set resp.http.X-Cache = "Miss via" + server.ip;
}
}
varnish日志区域:
1、varnishstat - Varnish Cache statistics
-1 //显示一次
-1 -f FILED_NAME
-l:可用于-f选项指定的字段名称列表;
MAIN.cache_hit
MAIN.cache_miss
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
# varnishstat -l -f MAIN -f MEMPOOL
2、varnishtop - Varnish log entry ranking
-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;
-I <[taglist:]regex>
-x taglist:排除列表
-X <[taglist:]regex>
3、varnishlog - Display Varnish logs
4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format
systemctl start varnishncsa.service //开启日志功能服务