能用到缓存的服务器的原因是,应用到了程序的局部性。
空间局部性:一个程序最近访问了一个空间,那么他周边的空间也将被访问。 时间的局部性:一条指令一段时间内被执行,之后的一段时间还会被执行。 衡量缓存的效率使用的缓存命中率: 文档命中率: 按照文档的数量进行衡量,10000 命中2000,就是1/5 字节命中率: 按照字节数量进行衡量,比如之前命中的两个为为100M,后面的八个为100K,那么按照数量来衡量命中率就最好用字节来衡量了。 缓存经历流程
浏览器缓存-->上游服务器缓存CDN-->反向代理的缓存-->真正原始服务器
varnish 的配置文件
1.用于定义各后端节点; 2.定义缓存机制 varnish的九个状态引擎 图: 每一个状态都有一个状态码,指明下一步如何进行。 vcl_pipe()表示不识别直接交给后端,只是在vcl_recv和后端主机之间建立了一个管道。 vcl_pass()表示略过,这是针对的不可缓存的对象 vcl_recv()是接受用户请求判断用户的请求首部,然后返回状态码pipe(不识别)|pass(不可缓存)|(error)(请求被拒绝)|lookup(交给hash查询)。 vcl_error()表示直接返回错误信息 vcl_hash():对用户的请求首部url做hash计算,查看是否有缓存。 vcl_hit ():表示内容被命中 vcl_miss():表示未命中 vcl_pass():如果是 对于不可缓存的对象,通过vcl_fetch建立客户端与后端主机,让后端主机直接给予应答,之后也不会给予缓存。 vcl_fetch():这是在后端主机更新缓存是时使用,1.如果请求是可缓存,并且规则允许缓存时,那么经过vcl_fetch,此时会给予链接至后端主机,由后端主机响应数据给客户端,然后本地缓存。2.如果请求是可以缓存的,但是我们本地规则设置不允许缓存的,我们给予建立后端链接,让客户端响应,本地不给于缓存。3.对于不可以缓存的,直接建立后端链接,让后端主机响应,本地不做缓存。
下载安装varnish包: 1
2
3
4
5
6
7
8
| lftp172.16.0.1:/pub/Sources/6.x86_64/varnish> mget ./varnish*
881392 bytes transferred Total 4
files transferred
lftp 172.16.0.1:/pub/Sources/6.x86_64/varnish> bye
[iyunv@localhost haproxy ]# ls
varnish-docs-3.0.6-1.el6.x86_64.rpm //varnish的文件
varnish-3.0.6-1.el6.x86_64.rpm
varnish-libs-3.0.6-1.el6.x86_64.rpm //varnish的库文件
|
安装生成文件: 配置文件: 这是关键配置文件,进程自己的工作属性 /etc/sysconfig/varnish 定义代理的工作属性 /etc/varnish/default.vcl 配置文件的修改 1
2
3
4
5
6
7
8
9
10
11
12
13
| [iyunv@localhost sysconfig ]# vim varnish
# Maximum number of open files (for ulimit -n)
8 NFILES=131072 //可以打开的最大文件数
10 #Locked shared memory (for ulimit -l)
11 #Default log size is 82MB + header
12 MEMLOCK=82000 //日志的最大首部大小
15 NPROCS="unlimited"
66 VARNISH_LISTEN_PORT=6081
89 #VARNISH_STORAGE_SIZE=1G
90 VARNISH__MALLOC_SIZE=512M //指定存储的大小
91 # #Backend storage specification
#VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" //指定存储的类型
VARNISH_STORAGE="malloc,,${VARNISH_MALLOC__SIZE}" //这
|
里是使用内存的方式 1.自定义配置文件的名字 我们使用test.vcl 代替default.vcl 1
2
3
4
5
6
| [iyunv@localhost varnish ]# mv default.vcl test.vcl //我们还需要到进程配置文件的,修改默认的配置文件名
59 # #Main configuration file. You probably want to change it :)
60 #VARNISH_VCL_CONF=/etc/varnish/default.vcl
61 VARNISH_VCL_CONF=/etc/varnish/test.vcl //这样我们重启就可以是实现修改默认配置文件了
#service
varnish restart
|
#但是缓存服务器一般不会重启,我们使用的方式是: 1
2
3
4
5
6
7
8
9
10
11
12
13
| [iyunv@localhost
etc ]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
200
varnish>
vcl.load t1 test.vcl
200
varnish>
vcl.use t1
varnish>
vcl.list
200
available 0 boot
active
|
2.定义单个后端主机: 格式: 1
2
3
4
5
| Backend
nodename {
.host = "ipaddr"; //分号结尾
.port = "port"; //点号开头
}
|
例如: 7 backend default { 8 .host = "172.16.249.248"; 9 .port = "80"; 10 } 3.定义deliver投递方式: 我们自己定义一个变量:set 设置自定义首部。 + 用于连接字符串。 这里我们的代理配置文件定义一个默认后端主机: 定义一个后端主机:然后开器deliver状态引擎。: 1
2
3
4
5
6
7
8
9
10
11
12
13
| 7 backend default {
8 .host = "172.16.249.220";
9 .port = "80";
10 }
sub vcl_deliver {
116 if(obj.hits > 0) {
117 set resp.http.X-Cache = "HIT via" + " " + server.hostname;
118 }
119 else {
120 set resp.http.X-Cache ="MISS";
121 }
122 return(deliver);
123 }
|
4.内置变量: 五类: Req ,resp ,bereq ,beresp ,obj 请求类: Sever.ip 服务端IP Serve.hostname 主机名 Req.backend 指定对应主机名 Req.url 指定请求的地址 Req.http.header 指定请求http协议头部信息。 Req.quest指定请求方法 Req.http.x-forword-for 转发上一级的IP信息 Req.http 响应类: Resp.response 响应给客户端的http信息 Resp.http.header 返回给客户端的http头部信息 Resp.status 响应的状态码 bereq由varnish向后端主机的请求类 beReq.url 指定请求的地址 beReq.http.header 指定请求http协议头部信息。 beReq.quest指定请求方法 由后端主机向varnish响应的变量 Beresp.request 指定请求的类型 Beresp.url 指定请求的路径 Beresp.http.header 请求的首部信息 Beresp.ttl 缓存的保留时长 关于获取内容的变量 Obj.status 请求状态码 Obj.ttl 缓存时间 Obj.hits 命中次数 5.VCL语法: vcl是基于域的编程语言,支持算数运算和逻辑运算们支持正则表达式。支持set自定义变量,支持unset撤销变量,支持if条件判断,有内置的函数和变量; 保存于vcl配置文件中;此配置文件需要编译为二级制方式,才能使用。 后端节点backend name {} 代理缓存 Sub 来定义状态引擎。 是由manager进程调用gcc,编译然后交给子进程使用。 状态引擎有很大的相关性:return(X)定义退出状态,进而决定继续处理的下一个引擎。 vcl的语法格式: 1.注释:使用//, /*多行注释*/ 2.sub $name 定义函数 3.不支持循环 4.支持条件判断 5.支持终止语句 6.域专用 7.操作符:=,==,~,!, 支持正则表达式 vcl内置函数: Regsub(str,pattern,sub) 按照正则表达式,把str换成sub Regsubball(str,regexp,sub) 全局】 Hash_data(str) Purge:从缓存中挑选出对象并删除 return() 例如:vcl-recl 可以返回pass,pipe,lookup,error 6.if语句的使用语法结构: 语法的使用: If 语句 单分支{ } 多分支 If(condition){ …; } Else{ …; } 7.定义某类内容被缓存: 注意这里面模式匹配的内容要用到引号引起来。语法把他们当做语法。 1
2
3
4
5
6
7
8
9
10
11
| 38 if (req.http.Authorization || req.http.Cookie) {
39 /* Not cacheable by default */
40 return (pass);
41 }
42 if (req.url ~".(jpg|jpeg|png|gif)$"){ //如果是以这些结尾
43 if(req.http.Cookie){ //如果有cookie
44 unset req.http.Cookie; //清除cookie
45 }
46 }
47 return (lookup); //返回查询状态码
48 }
|
我下线httpd ,查看是否缓存下来 8.基于ACL的支持访问控制机制: 使用格式: Aclname { "ip"; "net"; //注意在;这里如果是一个网段掩码要在外面 "172.16.0.0"/16; }
这种情况,我们一般用在特殊,需要控制的范围。例如:清除缓存。 9.error内置命令的使用 Error code 直接生成一个响应页面,这个页面可以是完成的,也可以是错误的。 常用code有 200 405" " 10.清除缓存purge的设定 1.首先设置访问控制,只允许本机和IP172.16.249.141访问。 1
2
3
4
5
| acl purges {
12 "127.0.0.1";
13 ="localhost";
14 "172.16.249.141";
15 }
|
2.配置purge规则 自定义一个请求方法比如是PURGE。 如果用用户是通过我们定义的主机使用的purge方法,允许清除对应的缓存,如果不是返回错误页面。 如果没有命中要清除的缓存,也返回提示错误页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| backend default {
8 .host = "172.16.249.248";
9 .port = "80";
10 }
#对purges设置权限
11 acl purges {
12 "127.0.0.1";
13 "localhost";
14 "172.16.249.141";
15 }
23 sub vcl_recv {
24 if (req.restarts == 0) {
25 if (req.http.x-forwarded-for) {
26 set req.http.X-Forwarded-For =
27 req.http.X-Forwarded-For + ", " + client.ip;
28 }else {
29 set req.http.X-Forwarded-For = client.ip;
30 }
31 }
#定义请求方法,允许使用PURGE
32 if (req.request != "GET" &&
33 req.request != "HEAD" &&
34 req.request != "PUT" &&
35 req.request != "POST" &&
36 req.request != "TRACE" &&
37 req.request != "OPTIONS" &&
38 req.request != "DELETE" &&
39 req.request != "PURGE") {
40 /* Non-RFC2616 or CONNECT which is weird. */
41 return (pipe);
42 } #定义请求方法,允许使用PURGE
43 if (req.request != "GET" && req.request !="HEAD" && req.request != "PURGE") {
44 /* We only deal with GET and HEAD by default */
45 return (pass);
46 }
47 if (req.http.Authorization || req.http.Cookie) {
48 /* Not cacheable by default */
49 return (pass);
50 }
51 if (req.request =="PURGE") {
52 if (!client.ip ~purges){
53 error 405 "forbidding";
54 }
55 }
56 if (req.url ~ ".(jpg|jpeg|png|gif)$"){
57 if(req.http.Cookie){
58 unset req.http.Cookie;
59 }
60 }
61 return (lookup);
62 }#定义命中状态引擎,命中执行purge函数
92 sub vcl_hit {
93 if (req.request == "PURGE"){
94 purge;
95 error 200 "finished";
96 }
97 }#定义非命中状态引擎, 错误引擎
102 subvcl_miss {
103 if (req.request == "PURGE"){
104 purge;
105 error 404 "no cache";
106 }
107 }
|
11.自定义那些内容可以缓存,以及缓存时长 1
2
3
4
5
6
7
8
| 124 sub vcl_fetch {
125 if (req.url ~".(jpg|jpeg|png|gif)$"){
127 set beresp.ttl = 3600 s;
128 return(deliver);}
129 if (req.url ~ ".(php|cgi)$"){
130 set beresp.ttl = 0 s; }
131 return(deliver);
132 }
|
12.健康状态检查: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| .probe = { //可以单独定义,也可以在backend中定义
.url =# //指明路径
.request =#
//定义请求格式
.windowns =#
//基于最近多少次检查,是失败还是成功。这里是8次
.threshold =
# 这里是必须成功了5次才认为是健康的。
.initial =
# 成功多少次,才把后端主机设置为健康状态。
.expected_response=# //指定的时间
.interval = //间隔时间
.timeout =
}
例如:
probe dynamic {
.url = "/index.html";
.interval = 5s;
.timeout = 1s;
.expected_response= 200;
}
|
13.定义缓存的负载均衡和动静分离 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| backend app1 {
.host = "172.16.11.11";
.port = "80";
}
backend app2 {
.host = "172.16.11.12";
.port = "80";
}
backend web1 {
.host = "172.16.11.13";
.port = "80";
}
backend web2 {
.host = "172.16.11.14";
.port = "80";
}
director apps random { #定义一个后端服务器组,实现负载均衡效果
{
.backend = app1; #调用前面已定义过的后端主机
.weight = 2; #设置权重
}
{
.backend = app2;
.weight = 2;
}
}
director webs random { #定义后端静态服务器组,实现负载均衡效果
{
.backend = web1;
.weight = 2 ;
}
{
.backend = web2;
.weight = 2 ;
}
}
sub vcl_recv { #定义引用规则
if (req.url ~ ".php(?.*|$)") {
set req.backend = apps;
}else {
set req.backend = webs;
}
return(lookup);
|
varnish管理命令 跟随varnish会一起安装一些方便的调试工具,用好这些工具,对你更好的应用varnish有很大的帮助。
varnishncsa(以 NCSA 的格式显示日志)
通过这个命令,可以像类似于 nginx/apache一样的显示出用户的访问日志来。
varnishlog(varnish详细日志)
如果你想跟踪varnish处理每个请求时的详细处理情况,可以使用此命令。
直接使用这个命令,显示的内容非常多,通常我们可以通过一些参数,使它只显示我们关心的内容。
-b \只显示varnish和backend server之间的日志,当您想要优化命中率的时 候可以使用这个参数。
-c \和-b差不多,不过它代表的是 varnish和 client端的通信。
-i tag \只显示某个 tag,比如“varnishlog –i SessionOpen”将只显示新会话,注意,这个地方的tag名字是不区分大小写的。
-I \通过正则表达式过滤数据,比如“varnishlog -c -i RxHeader -I Cookie”将显示所有接到到来自客户端的包含 Cookie 单词的头信息。
-o \聚合日志请求 ID
varnishlog -c -o /auth/login 这个命令将告诉您来自客户端(-c)的所有包含”/auth/login” 字段(-o)请求。
varnishlog -c -o ReqStart 192.168.1.100 只跟踪一个单独的client请求
varnishtop
您可以使用varnishtop 确定哪些URL经常被透传到后端。
适当的过滤使用 –I,-i,-X 和-x 选项,它可以按照您的要求显示请求的内容,客
户端,浏览器等其他日志里的信息。
varnishtop -i rxurl \您可以看到客户端请求的 url次数。
Varnishtop -i txurl \您可以看到请求后端服务器的url次数。
Varnishtop -i Rxheader -I Accept-Encoding \可以看见接收到的头信息中有有多少次
包含Accept-Encoding。
varnishstat
显示一个运行varnishd实例的相关统计数据。
Varnish 包含很多计数器,请求丢失率,命中率,存储信息,创建线程,删除对象等,几乎所有的操作。通过跟踪这些计数器,可以很好的了解varnish运行状态。
varnishadm
通过命令行,控制varnish服务器。可以动态的删除缓存,重新加载配置文件等。
管理端口有两种链接方式:
1,telnet方式,可以通过telnet来连接管理端口.如:"telnet localhost 6082"
2,varnishadm方式,可以通过varnish自带的管理程序传递命令.如: varnishadm -n vcache -T localhost:6082 help
动态清除缓存
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 ban.url /2011111.png
其中:ban.url 后的路径一定不要带abc.xxx.com域名之类的,否则缓存清除不了。
清除包含某个子目录的URL地址:
/usr/local/varnish/bin/varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 url.purge /a/
不重启加载配置文件
登陆到管理界面
/usr/local/varnish/bin/varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
加载配置文件
vcl.load new.vcl /etc/varnish/default.vcl
编译出错的话会有提示,成功会返回200
加载新配置文件
vcl.use new.vcl
此时新的配置文件已经生效!
|