软件包提取码:b17b
vcl语言进行集中管理
vcl中的模块:
- vcl_recv(receive) 用来接收客户端的请求
- vcl_hash(lookup) 如果请求的是静态数据则进入到varnish本身的缓存中
- vcl_pass(pass) 当请求为动态数据 则去后端获取 varnish不缓存动态数据
- vcl_pipe(pipe) 当请求为非正常请求时 则拒绝
- vcl_hit(hit) 在varnish缓存中找到对应数据(命中)
- vcl_miss(miss) 在varnish缓存中没有找到对应数据(未命中)
- vcl_fetch(fetch) 将请求交给后端
- vcl_deliver(deliver) 讲求请响应给客户端
预设变量: - req 客户端发送给varnish请求使用的变量
- req.url 客户端对varnish请求的url
- req.http 客户端对varnish请求的头部信息
- req.http.host 和互动最varnish域名
- bereq varnish给后端服务器发送的请求
- bereq varnish对后端服务器请求的url
- bereq.http 对后端服务器请求的头部信息
- resp varnish对客户端的响应
- resp.http varnish响应的头部信息
- resp.status 返回状态码
- beresp 服务器给varnish的响应
- beresp.uncacheable 响应数据是否不缓存
- beresp.ttl 响应数据缓存时间
- obj 缓存在varnish中的数据
- obj.ttl 缓存在varnish本地缓存的时间
- obj.hits varnish缓存的命中次数
- hash_data() 对客户端请求的内容进行hash计算
- hash_data(req.url)
- hash_data(rep.url.host)
- hash_data(server.ip)
vcl语法: -
运算符: =赋值运算符 == 比较运算符 ~正则匹配 !非 != 不等于 !~ 不匹配 && || 与非
-
数据类型: 字符串 “abc” 布尔值 true false 时间 s秒 m分钟 d天
- 条件谈判
-
if else
单主机实例
客户端 | 192.168.1.1 |
---|---|
varnish | 192.168.1.2 |
web | 192.168.1.3 |
[root@CentOS2 ~]# vim /usr/local/varnish/default.vcl
16 probe health {
17 .url = "/"; #从/开始
18 .timeout = 3s; #超时时间
19 .interval = 1s; #间隔时间
20 .window = 5; #能同时维持5个窗口运行
21 .threshold = 3; #至少3个成功
22 }
23 backend web { #后端主机
24 .host = "192.168.1.3";
25 .port = "80";
26 .probe = health;
27 }
28 sub vcl_recv { #用来接收客户端请求的模块
29 set req.backend_hint = web; #当请求命中后端web 才接收请求
30 if(req.http.X-Forwarded-For){#如果在客户端的请求头当中看到这个字段 则就证明经过了代理
31 set req.http.X-Forwarded-For=req.http.X-Forwarded-For+ "," +client.ip;
32 } #则需要重新建立请求头部把这个字段后面加上代理的ip和客户端的ip为了服务端能够获取到client的ip
33 else{
34 set req.http.X-Forwarded-For=req.http.X-Forwarded-For; #如果没有 不改变
35 }
36 if(req.method != "GET" &&
37 req.method != "POST" &&
38 req.method != "DELETE" &&
39 req.method != "HEAD" &&
40 req.method != "PUT" #如果请求是不正常的请求方式
41 ){
42 return(pipe); #则进入到pipe模块中
43 }
44 if(req.url ~ "\.(html|htm|png|jpg$)"){ #如果客户端的请求url中是以.html结尾 则是静态数据
45 return(hash); #则进入到hash模块中
46 }
47 if(req.url ~ "\.php$"){ #如果请求是以.php结尾 则是动态数据
48 return(pass); #则进入到pass模块中
49 }
50 return(hash); #其余全部进入到hash模块中
51 }
52 sub vcl_hash{ #静态数据模块
53 hash_data(req.url); #对客户端的请求路径进行hash
54 if(req.http.host){ #如果请求头当中包含域名
55 hash_data(req.http.host); #则hash域名
56 }
57 else{
58 hash_data(server.ip); #其余haship
59 }
60 }
61 sub vcl_pass{ #动态请求数据块
62 return(fetch); #直接将请求交给后端
63 }
64 sub vcl_pipe{ #不正常请求的模块
65 return(pipe); #直接结束
66 }
67 sub vcl_miss{ #缓存未命中
68 return(fetch); #直接将请求交给后端
69 }
70 sub vcl_hit{ #缓存命中
71 return(deliver); #直接响应
72 }
73 sub vcl_backend_response{ #后端数据模块
74 if(bereq.url ~ "\.php$"){ #如果varnish对后端请求的是动态数据 则不缓存
75 set beresp.uncacheable = true;
76 }
77 if(bereq.url ~ "\.html$"){ #如果varnish对后端请求的是静态数据
78 set beresp.ttl = 300s; #则缓存300s
79 }
80 }
81 sub vcl_deliver{ #结束模块
82 if(obj.hits > 0){ #如果命中次数大于0
83 set resp.http.X-cache = "hit~~";
84 } #则在varnish对客户端的响应头部建立hit~~~
85 else{
86 set resp.http.X-cache = "miss~~"; #其余 则在varnish对客户端的响应头部建立miss~~
87 }
88 }
[root@CentOS2 ~]# varnishd -C -f /usr/local/varnish/default.vcl #检测语法
[root@CentOS2 ~]# varnishd -f /usr/local/varnish/default.vcl #启动服务
客户端验证:
[root@CentOS1 ~]# curl -I 192.168.1.2
HTTP/1.1 200 OK
Date: Mon, 22 Jun 2020 03:01:07 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Mon, 22 Jun 2020 03:00:36 GMT
ETag: "c-5a8a3726a3545"
Content-Length: 12
Content-Type: text/html; charset=UTF-8
X-Varnish: 2
Age: 0
Via: 1.1 varnish-v4
X-cache: miss~~~ #第一次为miss
Accept-Ranges: bytes
Connection: keep-alive
[root@CentOS1 ~]# curl -I 192.168.1.2
HTTP/1.1 200 OK
Date: Mon, 22 Jun 2020 03:01:07 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Mon, 22 Jun 2020 03:00:36 GMT
ETag: "c-5a8a3726a3545"
Content-Length: 12
Content-Type: text/html; charset=UTF-8
X-Varnish: 5 3
Age: 2
Via: 1.1 varnish-v4
X-cache: hit~~~ #第二此为hit
Accept-Ranges: bytes
Connection: keep-alive
多主机实例
[root@CentOS2 ~]# vim /usr/local/varnish/default.vcl
probe health {
.url = "/";
.timeout = 3s;
.interval = 1s;
.window = 5;
.threshold = 3;
}
backend web1 {
.host = "192.168.1.3";
.port = "80";
.probe = health;
.max_connections = 100;
}
backend web2 {
.host = "192.168.1.4";
.port = "80";
.probe = health;
.max_connections = 100; #最大连接
}
acl allow { #访问控制列表 allow是名称
"127.0.0.1"; #本地回环
"localhost"; #域名主机名
"192.168.1.2"; #ip
}
import directors; #导入集群模块
sub vcl_init{ #导入轮询模块
new back = directors.round_robin(); #使用动态轮询的方式
back.add_backend(web1); #使用上面的主机
back.add_backend(web2);
}
sub vcl_recv{
set req.backend_hint = back.backend(); #自动屏蔽掉后端不正常的主机
if(req.method == "PURGE"){ #当请求方式为purge
if(client.ip !~ allow){ #如果请求的ip不匹配allow列表
return(synth(405,"not allowed")); #将返回状态码405
}
else{
return(purge); #其余则进入到清除缓存的模块
}
}
if(req.http.host ~ "^qqq"){ #如果客户端的请求域名是以qqq开头
set req.backend_hint = web1; #则将请求交给web1
}
if(req.http.host ~ "^www"){ #如果客户端的请求域名是以www开头
set req.backend_hint = web2; #则将请求交给web2
}
if(req.url ~ "\.(php|asp|aspx|jsp|do)($|\?)"){ #如果请求的是动态数据
return(pass); #则把请求交给pass模块
}
if(req.url ~ "\.(css|html|htm|jpeg|png|mp4)$"){ #如果请求是静态数据
return(hash); #则把请求交给hash模块
}
if(req.method != "GET" &&
req.method != "POST" &&
req.method != "DELETE" &&
req.method != "PUT" &&
req.method != "HEAD"
){
return(pipe); #如果请求方式不是正常的请求方式 #则拒绝连接
}
if(req.method != "GET" && req.method != "HEAD"){ #当请求方式不是get或者head是
return(pass); #则进入到动态数据模块 因为其余的请求方式和数据库都是有联系的
}
if(req.http.Authorzation){ #如果请求是认证
return(pass); #则进入到pass模块中
}
if(req.http.Accept-Encoding){ #如果在客户端的请求头中有这个字段
if(req.url ~ "\.(png|gif|bz2|zip)$"){ #客户端如果请求的是压缩文件
unset req.http.Accept-Encoding; #则不用建立这个请求头 防止web再次压缩
}
elseif(req.http.Accept-Encoding ~ "gzip"){ #如果请求头中匹配到gzip
set req.http.Accept-Encoding = "gzip"; #则建立这个请求头
}
elseif(req.http.Accept-Encoding ~ "deflate"){
set req.http.Accept-Encoding = "deflate";
}
else{
unset req.http.Accept-Encoding; #其余则不用建立
}
}
}
sub vcl_pipe{ #拒绝连接模块 直接结束
return(pipe);
}
sub vcl_pass{ #动态数据模块 进入到后端
return(fetch);
}
sub vcl_hash{ #静态数据模块
hash_data(req.url); #hash请求的路径
if(req.http.host){
hash_data(req.http.host); #hash域名
}
else{
hash_data(server.ip); #其余hash ip
if(req.http.Accept-Encoding ~ "deflate"){ #当请请求头部有这个字段 则hash deflate
hash_data("deflate");
}
if(req.http.Accept-Encoding ~ "gzip"){ #如果客户端请求头部中包含编码类型 web是以压缩文件进行传输的 是由客户端
hash_data("gzip"); 本身来进行解压 那么为了varnish能够把压缩有的文件进行缓存 所以填写了这个
} Accept-Encoding字段
}
}
sub vcl_backend_response{ #后端能够找到对应的数据
if(bereq.url ~ "\.(php|asp|do)($|\?)"){ #当时动态数据时
set beresp.uncacheable = true; #不缓存 直接响应给客户端
return(deliver);
}
if(bereq.url ~ "\.(css|html|htm|png)$"){ #静态数据
set beresp.ttl = 15m; #缓存15分钟时间
}
if(bereq.url ~ "\.(gz|bz2|zip|mp3)$"){ #压缩文件
set beresp.ttl = 300s; #缓存300s
}
return(deliver);
}
sub vcl_backend_error{ #后端找不到对应的数据
if(beresp.status == 503){ #当状态码为503
set beresp.status = 200; #把状态码换成200
synthetic("hahahaha"); #返回页面 hahahaha
return(deliver);
}
}
sub vcl_purge{ #清除缓存模块
return(synth(200,"success~~~~")); #状态码变成200 成功
}
sub vcl_deliver{ #结束模块
if(obj.hits > 0){ #如果命中次数大于0
set resp.http.X-cache = "hit~~~~~"; #则在varnish对客户端的响应头部建立hit~~
}
else{
set resp.http.X-cache = "miss~~~~"; #其余 则在varnish对客户端的响应头部建立miss~~
}
}
root@localhost ~]# killall -9 varnishd
[root@CentOS2 ~]# varnishd -f /usr/local/varnish/default.vcl
验证
客户端访问
[root@CentOS ~]# curl -I 192.168.1.2
X-cache: miss~~~~
[root@CentOS ~]# curl -I 192.168.1.2
X-cache: hit~~~~
客户端清除缓存
[root@CentOS ~]# curl -I http://192.168.1.2 -X PURGE
HTTP/1.1 405 not allowed
varnish清除
[root@CentOS ~]# curl -I http://192.168.1.2 -X PURGE
HTTP/1.1 200 success~~~~
错误页面是否能访问成功
把varnish的缓存清除
后端的web关掉
客户端访问的
[root@CentOS ~]# curl -I 192.168.1.2
HTTP/1.1 200 OK
[root@CentOS ~]# curl 192.168.1.2
hahahaha
访问qqq www出两个页面
后端服务开启
反向代理清除缓存 varnish重启
客户端:
[root@CentOS ~]# vim /etc/hosts
192.168.1.2 www.abc.com 反向代理的ip
192.168.1.2 qqq.abc.com
[root@CentOS ~]# curl www.abc.com
1111
[root@CentOS ~]# curl qqq.abc.com
2222