上缓存服务器的目的:

1、减少clint对后端服务器的访问压力。

2、在静态资源较多的情况下,服务端可以快速对clint的访问做出相应。


缓存服务器目前比较有名气,市面上缓存代理服务器使用比较多的Varnish/squid。


squid的主要是缓存大文件。

Varnish主要缓存静态资源,如图片。


Varnish版本的区别:

新版本Varnish4,client/backend分离,新的vanishlog查询语言,安全方面据说有提升。


首先是必须定义版本号: vcl 4.0。VMOD’s更独立化,官方推荐是加载Standard VMOD’s(std)。


另外director已变为VMOD,如需使用,需要import directors。


vcl_fetch函数被vcl_backend_response和vcl_backend_fetch代替,且req.*不再适用vcl_backend_response,只能使用bereq.*。


至于vcl_backend_fetch貌似没哪个doc见到详细用法。


error变更为return(synth(http_code,message)),req.backend成了req.backend_hint,req.request变更为req.method,obj为只读对象了。


vcl_synth采用resp.*,而非原来的obj.*。


vcl_error变更为vcl_backend_error,必须使用beresp.*,而不是obj.*。


关键字"purge;"命令,已被去除。在vcl_recv使用return(purge)。


hit_for_pass通过set beresp.uncacheable = true;来指定。


vcl_recv必须将lookup变更返回hash,vcl_hash必须将hash变更返回lookup,vcl_pass必须将pass变更返回fetch。


req.backend.healty被std.healthy(req.backend)代替,但是设置不了grace,鸡肋,被抛弃了,现在仅能做的就是keepalive的作用了。


req、bereq,resp、beresp之间不同,可被使用的位置不同。


server.port、client.port分别变更为std.port(server.ip)、std.port(client.ip),跟上面healthy一样,需要import std。


session_linger变更为timeout_linger,sess_timeout变更为timeout_idle,sess_workspace被抛弃了。


remove被完全弃用了,不过我一直用unset的说。


return(restart)变更为return(retry),vcl_backend_fetch会被使用到。


自定义sub函数不能以vcl_开头,调用方式call udf。



部署架构:单节点/双节点

1、如果你们的服务在云节点部署那久简单了,流行的云平台都有负载均衡器(HA/LB)等等,部署2台Varnish 挂载后端nginx 就完事了。

2、如果你们自建机房,Varnish的前端代理可以选择(Nginx/HA),这2套开源软件都比较流行,做代理性能也不错。


下面是大致的Varnish逻辑图:

第一种全部单节点:

wKioL1kLBk2iZxL6AABLM0_SbKg584.png


第二种Varnish双节点,Nginx单节点:

wKioL1kLBn6Tf3otAABfg78JJN4551.png


第三种双节点:

wKioL1kLBq3T8-APAAB1PhnSBsA411.png


 Varnish的安装上篇已经写过,请参考之前的博客;


Varnish配置参数:

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
cat  /etc/sysconfig/varnish
# Maximum number of open files (for ulimit -n)  #打开文件的最大个数,limit可以修改
NFILES=131072
# Default log size is 82MB + header   #日志文件大小82M
MEMLOCK=82000
# Maximum number of threads (for ulimit -u)  #最大线程数,使用unlimited变量
NPROCS= "unlimited"
# Maximum size of corefile (for ulimit -c). Default in Fedora is 0  #打开的最大核心文件数,Fedora默认是0  
# DAEMON_COREFILE_LIMIT="unlimited"
# Set this to 1 to make init script reload try to switch vcl without restart.
# To make this work, you need to set the following variables
# explicit: VARNISH_VCL_CONF, VARNISH_ADMIN_LISTEN_ADDRESS,
# VARNISH_ADMIN_LISTEN_PORT, VARNISH_SECRET_FILE, or in short,
# use Alternative 3, Advanced configuration, below
RELOAD_VCL=1     #如果配置为1,重新load varnish配置文件vcl,varnish服务器不会重启,可能是热加载吧,不清楚使用默认
# # Main configuration file. You probably want to change it :)
VARNISH_VCL_CONF= /etc/varnish/default .vcl       #Varnish默认加载的配置文件
# VARNISH_LISTEN_ADDRESS=  #Varnish监控的端口,改为80,修改的
VARNISH_LISTEN_PORT=80
# # Telnet admin interface listen address and port   #Varnish的管理端口
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
# # Shared secret file for admin interface
VARNISH_SECRET_FILE= /etc/varnish/secret     #Varnish的secret文件,默认
# # The minimum number of worker threads to start   #Varnish最小线程数
VARNISH_MIN_THREADS=50
# # The Maximum number of worker threads to start
VARNISH_MAX_THREADS=4000         #Varnish最大线程数,默认1000,不超过5000 应该没问题
# # Idle timeout for worker threads
VARNISH_THREAD_TIMEOUT=120       #超时
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
VARNISH_STORAGE_SIZE=512M      #Varnish使用的空间大小默认
# # Backend storage specification
VARNISH_STORAGE= "malloc,${VARNISH_STORAGE_SIZE}"    #存储空间使用内存,file是磁盘
# # Default TTL used when the backend does not specify one
VARNISH_TTL=120    #Varnish缓存时间120s


Varnish的配置文件,这块使用的版本4.0的,其他版本还是有区别的,Varnish官网到5版本了。


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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
[root@www varnish] # cat default.vcl 
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.
# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;
#导入directors模块,基于负载均衡调度,后端多个主机可以使用轮询
import  directors;
# Default backend definition. Set this to point to your content server.
#这块以单节点演示
backend web1 {
     .host =  "172.16.2.27" ;
     .port =  "80" ;
}
#注意:用户请求成功后,对请求的数据做处理,varnish4走缓存使用return (hash); varnish3走缓存使用 return(lookup);还是有区别的。
sub vcl_recv {    
    if  (req.http.host ~  "(www.)?laiwojia.la" ) {   #如果请求的是www域名就走web1
     set  req.backend_hint = web1;
}
#return(hash);#否则就走hash;这条最好写到vcl_recv配置末尾,这是if判断,除了www走web1,其余url都是hash,后续的测试pass的你会发现全是命中,注释掉此行后才会pass
     if  (req.url ~  "(?i)^/(login|admin)" ) { #登录pass
     return (pass);
}
     if  (req.url ~  "(?i)\.php$" ) { #访问url是php结尾走web1
         set  req.backend_hint = web1;
     }
     if  (req.url ~  "(?i)\.(jpg|jpeg|png|gif|css|js)$" ) { #图片走web1
     set  req.backend_hint = web1;
}
####注意:varnish4.*版本使用时req.method;varnish3.*的版本使用req.request,这点要注意
if  (req.method != "GET"  && req.method !=  "HEAD"  && req.method !=  "PUT"  && req.method !=  "POST"  && req.method !=  "TRACE"  && req.method !=  "OPTIONS"  && req.method !=  "PATCH"  &&  req.method !=  "DELETE" ) {
     return  (pipe);
}
if  (req.http.Upgrade ~  "(?i)websocket" ) {
     return  (pipe);
   }
if  (req.method !=  "GET"  && req.method !=  "HEAD" ) {
     return  (pass);
   }
   #下面这段是我看到别人github上的资源,发现比较全摘录的,压缩、图片、视频流、文档等,访问这些资源不保存cookie信息;
if  (req.url ~  "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$" ) {
     unset  req.http.Cookie;
     return  ( hash );
   }
   #这段其实和上面的有些重复,二选一或者全保留也没错,
if  (req.http.Authorization || req.http.Cookie) {
     return  (pass);
}
if  (req.url ~  "test.html" ) {  #这是上面测试的,如果请求的是test.html 就pass,之前return (hash),写在上面,怎么访问都是hit,查看配置文件
     return  (pass);
}
     return  ( hash ); #否则就走缓存,3.0还是2.0貌似都是return (lookup),4.0 是return (hash),我尝试些lookup 运行发现报错
}
#对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长
下面是服务器端对缓存服务器的响应
sub vcl_backend_response {
     if  (beresp.http.cache-control !~  "s-maxage" ) {
         if  (bereq.url ~  "(?i)\.(jpg|jpeg|png|gif|css|js)$" ) {
             unset  beresp.http.Set-Cookie;
             set  beresp.ttl = 3600s;
         }
}
      if  (bereq.http.host ==  "(www.)?laiwojia.la" ) {
         if  (bereq.url ~  "(?i)/api/product/hotlist"
            ||bereq.url ~  "(?i)/api/dolphin/list"
            ||bereq.url ~  "(?i)/api/product/baseInfo"
            ||bereq.url ~  "(?i)/api/product/desc"
            ||bereq.url ~  "(?i)/api/search/brandRecommendProduct"   
            ||bereq.url ~  "(?i)/cms/view/h5/headlinesList"   
            ||bereq.url ~  "(?i)/cms/view/h5/category"       
            ||bereq.url ~  "(?i)/cms/view/h5/article"       
            ||bereq.url ~  "(?i)/cms/view/h5/\w+\.html"     
            ||bereq.url ~  "(?i)/api/product/distributions" )
         {
          set  beresp.ttl = 300s;   // 缓存时间改为5分钟
         }
         elseif (bereq.url ~  "(?i)/api/search/searchList\?sortType=volume4sale_desc\&companyId=10\&keyword=\*\*\*\*\*\&pageSize=10"  )
         {
           set  beresp.ttl = 60s;   // 设置为1分钟
         }
         elseif (bereq.url ~  "(?i)/cms/view/.*/templateJS\.json" 
               ||bereq.url ~  "(?i)\.html" )
         {
           set  beresp.ttl = 600s;   // 设置为10分钟
         }
         elseif (bereq.url ~  "(?i)/libs/" )
         {
            set  beresp.ttl = 1800s;
         }
             set  beresp.grace = 2m;
}
}
sub vcl_pipe {
if  (req.http.upgrade) {
     set  bereq.http.upgrade = req.http.upgrade;
   }
     return  (pipe);
}
sub vcl_pass {
#return (pass);
}
sub vcl_hash {
     hash_data(req.url);
     if  (req.http.host) {
         hash_data(req.http.host);
else  {
          hash_data(server.ip);
}
if  (req.http.Cookie) {
     hash_data(req.http.Cookie);
   }
}
sub vcl_hit {
     if  (obj.ttl >= 0s) {
     return  (deliver);
}
}
sub vcl_miss {
     return  (fetch);
}
#结果投递,下面二选一都行
#响应
#sub vcl_deliver {
#    if (obj.hits > 0) {
#       set resp.http.X-Cache = "Hit"+server.ip; //服务器响应返回"HIT" + Varnish server ip
#     } else {
#       set resp.http.X-Cache = "Miss"; //返回未命中
#     }
#}
sub vcl_deliver {
     set  resp.http.X-Age = resp.http.Age;   #响应返回Age,
     unset  resp.http.X-Age;
     if  (obj.hits > 0) {
         set  resp.http.X-Cache =  "HIT" +server. hostname ; #服务器响应只返回命中或者未命中;
     else  {
         set  resp.http.X-Cache =  "MISS" ;
     }
}


需要配置文件参考的可以直接博客回复;

Varnish的常用命令:

重新载入配置文件:varnish_reload_vcl

wKiom1kLCWChUWe9AAD3u2Unuio395.png


查看Varnish的日志常被缓存的资源:varnishlog

wKiom1kLCbfhitSdAAEnBrvqJKk244.png


另一种查看日志的姿势:varnishncsa

wKiom1kLCqWgBKQAAABFr73tPBE351.png


Varnish的管理端口命令:varnishadm

wKiom1kLC2ThWRCqAAB8S9zSnz8047.png


查看varnish命中比率:varnishstat

wKioL1kLC6mAxgEMAADFbfWpSuM682.png

图标查看varnish命中:varnishhist

wKioL1kLEpiTnJ-wAABtYyX5IJs927.png

配置测试:

第一种测试:直接略过Varnish,直接访问nginx测试:

通过linux自带命令curl访问

wKiom1kLEw2D2fcOAABM2H1DE2I047.png

查看nginx日志:

wKiom1kLEzHQAfUBAAC2meT4Qcw289.png


第二种访问域名,域名解析在Varnish这台主机:

curl域名测试:

wKiom1kLE2vSKKQQAACjsWhk7fo894.png

查看结果:

wKiom1kLE4LxEWO4AAA3PKV3dlw251.png


第三种:通过web 浏览器访问,查看命中:

wKioL1kLE7SSzuvlAAKrVLw04QA642.png

第四种测试:

改变index.html文件内容,测试结果:第一次都不会命中,第二次/第三次全部命中。

wKiom1kLFCTCekZXAACjsWhk7fo218.png

配置Varnish,只要是test.html文件就pass,测试结果:

wKiom1kLFG6iPIbuAACNPYAJdWQ252.png


以下是return (pass)和return (pipe)的区别,摘录别人的博客:


调用 pass 函数,从后端服务器调用数据。 

 

调用 pipe 函数,建立客户端和后端服务器之间的直接连接,从后端服务器调用数据。 

 

调用hash函数,从缓存中查找应答数据并返回,如果查找不到,则调用pass函数从后端服务器

调用数据 。 


http 建立连接的过程  

 

http 请求的类型:get post head 

先说http建立连接的过程

 

当浏览器想要获得一个网页内容时,如在浏览器输入www.google.com。 

 

这时浏览器开始跟服务器建立连接,先执行三次握手,确认建立连接。 

 

之后浏览器会发送请求,一个网页包含多个内容,如图片,正文,html代码,css代码,js代码。

如果在html 1.0版本中,请求一个文件是需要建立一次连接的,多个请求多个连接。开销是很大的。

而在HTML 1.1中,具有了长连接的特性,允许在keep-live 时间内保持连接,在这段时间内无须

再建立连接就可以发送多个请求。 

 

请求完成 或 keep-live时间到限,连接断开。 

HTTP 请求的类型:

 

HTTP 请求的类型有几种,下面是主要的几种: 

  GET : 请求指定的页面信息,并返回实体主体。 

 HEAD: 只请求页面的首部。 

 POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。 

说白了,请求一个静态的HTML页面就是用get类型,而如果你在新浪微博上发一条微博,其实就是post 类型。

总结来说,get是请求相关URI并接受服务器的返回数据。为了接收数据。

post是发送数据给服务器,服务器需要对这些数据做相应的处理。为了发送数据。

 

以上都明白的话,就可以解答这三个问题了:

 

pass和pipe都从后端服务器取数据,它们之间有什么不同呢?  

  

什么情况下用pass,什么情况下用pipe呢?  

  

什么样的数据会被缓存在varnish中呢?  

 

问:pass和pipe都从后端服务器取数据,它们之间有什么不同呢?  

答:当vcl_recv调用 pass 函数时,pass将当前请求直接转发到后端服务器。而后续的请求仍然

通过varnish处理。 

例如,建立了HTTP连接之后,客户端顺序请求 a.css 、a.png两个文件,“当前请求”指的是第一个

请求,即a.css,a.css被直接转发到后端服务器,不被缓存。而后续的a.png则再由varnish来做

处理,varnish会判断a.png 如何处理。 

总结:一个连接中除了当前请求,其它请求仍然按照正常情况由varnish处理。 

 

而pipe模式则不一样,当vcl_recv判断 需要调用 pipe 函数时,varnish会在客户端和服务器之

间建立一条直接的连接 ,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish

检查请求,直到连接断开。 

 

什么情况下用pass,什么情况下用pipe呢?  

答:pass 通常只处理静态页面。即只在GET 和 HEAD 类型的请求中时才适合调用pass函数。

另外,需要注意的一点是,pass模式不能处理POST请求,为什么呢?因为POST请求一般是发送

数据给服务器,需要服务器接收数据,并处理数据,反馈数据 。是动态的,不作缓存。 

示例代码如下: 

if (req.request !="GET" && req.request != "HEAD") 

{               

return (pipe);       

}       

那什么情况下用pipe?由以上陈述可以知,类型是POST时用pipe,但是也许还不太清晰。举个例子,

当客户端在请求一个视频文件时,或者一个大的文档,如.zip .tar 文件,就需要用pipe模式,

这些大的文件是不被缓存在varnish中的。 

 

什么样的数据会被缓存在varnish中呢?   

答:varnish只缓存静态数据。在网上搜到的varnish缓存策略,可以解答这个问题: 

varnish缓存策略 

 

缺省是根椐后端返回的http状态码决定是否缓存。可以缓存的状态码如下: 

200    

203    

300    

301    

302    

410    

404 


这位大师的博客链接:http://yeelone.blog.51cto.com/1476571/772369/