设为首页 收藏本站
查看: 1156|回复: 0

[经验分享] varnish详解

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-6-8 08:39:43 | 显示全部楼层 |阅读模式
    Varnish是一款高性能的开源HTTP缓存加速器,从下图(网站拓扑结构视图)不难看出,缓存对于现代互联网的重要意义。
wKioL1Vy3eGRKug7AATFkGNpu3Q633.jpg
基础理论
缓存存在的基础
程序具有局部性
时间局部性
过去访问过的数据在一段时间内有可能被再次访问
空间局部性
过去被访问的某数据周围的其他数据有可能也被访问
缓存得以生效就是因为程序的局部性
缓存的存储方式
缓存以key-value形式存储
key:访问路径,url,经过hash计算后存储;
value:web content
缓存主要缓存的是热点数据
缓存命中率
hit/(hit+miss)
衡量标准
文档命中率:以命中文档的个数进行衡量;
字节命中率:以命中内容的大小进行衡量;
注意事项
1、缓存对象有生命周期,所以需定期清理;
2、当缓存耗尽时,可基于LRU(最近最少使用)算法,实时清理一部分缓存,以腾出空间存放新的缓存;
3、缓存需注意私密性,有些内容不可缓存,如用户的私有数据、报文首部中包含“Authorization,Cookie, Vary: accept-encoding=”等信息的;
缓存处理步骤
接收请求 --> 解析请求(提取请求的url及各种首部)--> 查询缓存 --> 新鲜度检测 --> 构建响应报文--> 发送响应 --> 记录日志
新鲜度检测机制
过期机制
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:
If-Unmodified-Since:
基于请求内容的时间戳作验证;
缺陷:若后端服务器内容改变频率为“毫秒”级,时间戳的最小单位为“秒”,此种验证会导致使用过期缓存;
If-Match:
If-None-Match:
对每个生成的内容作一个“Etag”标记,基于此特征码作验证;
常见缓存服务器开源解决方案
varnish,squid
缓存首先必须是一个反向代理
varnish基础
https://www.varnish-cache.org/
varnish工作架构图
wKiom1Vy3fzA7Yd8AAFVIBOjgxA386.jpg
Management管理进程:
编译VCL并应用新配置、监控varnish、初始化varnish并提供命令行接口CLI;
Child/Cache线程:
Acceptor:用于接收并连接请求;
Worker:用于处理并响应用户请求;
Object expiry:从缓存中清理过期的cache object;
cache-main:此线程只有一个,用于启动cache;
banluker:清理指定缓存;
expire:清理过期缓存
epoll:线程池管理器;
varnish定义其最大并发连接数是通过线程池模型实现的:
thread_pools:线程池个数,默认为2;
thread_pool_max:单线程池内允许启动的最大线程个数;
thread_pool_min:单线程池内允许启动的最小线程个数;
thread_pool_timeout:多于thread_pool_min的线程空闲此参数指定的时长后即被purge;
varnish的param查看及设置方法
使用“varnishadm”命令后使用如下命令实现:
param.show[-l] [param]
param.set[param] [value]
Log file:
varnish的日志,为保持其高性能,保持在一段共享内存空间中--Shared Memory Log,共享内存日志大小一般为90M,分为两部分:前一部分为计数器,后一部分为客户请求相关的数据,可以计算缓存命中率、分析请求首部、记录响应首部等;
vcl:Varnish Configuration Language
缓存策略配置工具;
基于“域”的简单编程语言,意为其所有代码都是写在各“{}”中,且作用范围仅为对应的“{}”,这些“域”称为varnish的状态引擎;
varnish定义其最大并发连接数:线程池模型:
thread_pools:线程池个数;默认为2;
thread_pool_max:单线程池内允许启动的最多线程个数;
thread_pool_min
thread_pool_timeout:多于thread_pool_min的线程空闲此参数指定的时长后即被purge;
vcl处理流程图
         wKioL1Vy3-ijNoqAAAF5Dwd-jl4714.jpg
         wKiom1Vy3lOBpplQAAE9pHjVWoA743.jpg

state engine
vcl配置的缓存策略在这些stateengine上发挥作用;state engine之间有相关性,上级engine通过return指明下级engine;varnish处理请求前要先分析该请求的http首部;
vcl_init:
在装载vcl,用其处理任何请求之前;
vcl_recv
请求被接入,但在其被分析、处理完成之前;
是否响应此请求、如何响应、使用哪个后端主机响应;
vcl_pipe
vcl_hash
vcl_hit
vcl_miss
vcl_pass
vcl_fetch
从backend主机收到响应报文之前被调用;可return的值:deliver、errorcode [reason]、restart;
vcl_deliver
vcl_error
配置文件
lftp172.16.0.1:/pub/Sources/6.x86_64/varnish> mget *.rpm(源码包位置)
varnish-3.0.6-1.el6.x86_64.rpm、varnish-libs-3.0.6-1.el6.x86_64.rpm、varnish-docs-3.0.6-1.el6.x86_64.rpm(此包非必须,仅用于提供各种说明文档)、varnish-libs-devel-3.0.6-1.el6.x86_64.rpm(若不做二次开发,此包无需安装)
/etc/varnish/default.vcl
配置语法
(1) //,#,注释单行,/*comment*/注释多行;
(2) sub $NAME用于定义函数,但函数不接受参数;
(3) 不支持循环;
(4) 支持众多内置变量;
(5) 支持使用终止语句,但没有返回值;
(6) “域”专用语言,即所写代码只能应用在特定的域上;
(7) 支持众多操作符:=,==,~,!,&&,||;
varnish命令行工具
varnishadm
varnishadm [-t  timeout]  [-S secret_file]  [-T address:port] [-nname] [command [...]]
vcl.load:重载
vcl.use:使用
vcl.show:显示
vcl.discard:删除
varnishd
varnishd [-a address[:port]] [-b host[:port]][-d] [-F] [-f config]
-a:指明监听的地址和端口,默认端口为6081;
-b:指明后端主机和端口;
-d:打开debug模式;
-F:运行于前台;
-f:指明配置文件;
-l:指明用于保存日志文件的内存空间大小;
-s[name=]type[,options]:指明使用的存储后端;
varnishtop
内存日志区域查看工具
-I regex:仅显示被模式匹配到的项目;
varnish支持的后端存储机制
-s type
malloc[,size]--在内存中保存缓存
file[,path[,size[,granularity]]]--在磁盘中使用单个文件保存所有缓存
persistent,path,size--持久保存,但目前仍处于测试阶段
注意:varnish进程一旦重启,前两种存储机制保存的所有缓存对象将被一律清空;对缓存来讲,预热十分重要,所谓预热即找出热点数据,保存在缓存中;
varnish配置
1、启动varnish前要先定义其脚本配置文件
配置打开资源限制段
NFILES=131072
多能打开的最大文件数,varnish会自动调整该值;
MEMLOCK=82000
所能使用的内存空间,varnish会自动调整该值;
NPROCS="unlimited"
单个用户所能运行的最大线程数;
RELOAD_VCL=1
定义varnish是否会自动重新装载其缓存策略配置文件;“=1”表示在我们使用脚本重启varnish时,其会自动重载vcl配置文件;
配置工作特性段
Alternative 1, Minimal configuration, no VCL
最小化配置,无缓存策略
Alternative 2, Configuration with VCL
使用vcl实现后续缓存配置
Alternative 3, Advanced configuration
高级配置,定义各种参数,默认使用此种配置方法
Alternative 4, Do It Yourself. See varnishd(1) formore information.
有如上4种可用配置选择,使用其中一种进行配置即可
采用Alternative 3的详细配置选项
VARNISH_VCL_CONF=/etc/varnish/default.vcl
缓存策略的默认读取文件;
VARNISH_LISTEN_PORT=80
因为varnish首先是作为web服务器的反向代理工作的,所以一般应监听于80端口;
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
client interface联系varnish的配置接口,一般此配置接口不应该允许远程打开,所以监听地址为本机;
VARNISH_SECRET_FILE=/etc/varnish/secret
使用client interface接口联系varnish时使用的密钥文件;
VARNISH_MAX_THREADS=3000
启用的最大线程数,因为varnish的并发能力有限,所以一般不要超过5000,否则可能导致不稳定;
#VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"
VARNISH_STORAGE="malloc,64M"
缓存默认保存在磁盘文件中,为了提高性能可修改为保存在内存中;
2、定义单个后端主机
# vim/etc/varnish/default.vcl
backenddefault {
  .host = "172.16.14.2";
  .port = "80";
}
编辑修改完vcl后必须重载配置文件才能生效,但是不建议重启varnish(会导致所有缓存清空),可使用如下方法实现:
#varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.list       //查看已有的vcl
200        
active         2 boot
varnish> vcl.loadtest1 ./default.vcl//编译刚刚修改的vcl
200        
VCL compiled.
varnish> vcl.list//显示刚修改的vcl已可使用
200        
active         2 boot
available      0 test1
varnish> vcl.use test1//重载修改过的vcl
200        
varnish> vcl.list//显示重载成功,已在使用
200        
available      2 boot
active         0 test1
3、定义多个后端主机
backend NAME {
.host=
.port=
}
vcl中条件判断的格式
单分支:
if(CONDITION) {
...;
}               
双分支:
if(CONDITION) {
...;
}else {
...;
}
多分支:
if(CONDITION1) {
...;
}elseif (CONDITION2) {
...;
}else {
...;
}
示例:在响应报文首部添加新首部以显示缓存的命中情况
sub vcl_deliver {
if(obj.hits>0){
setresp.http.X-Cache = "HIT";
}else {
set resp.http.X-Cache= "MISS";
}
}
网页测试结果
wKiom1Vy3oSgfh1XAAFqMt_RwCU791.jpg
vcl中常用变量
1、任何阶段(引擎)都可用的变量(图示任何阶段)
now:获取当前时间;
.host:后端主机IP地址或主机名;
.port:后端主机端口号或服务名;
2、处理请求阶段可用的变量(图示1)
client.ip:客户端ip;
server.hostname:varnish主机名;
server.ip:varnish ip;
server.port:varnish端口号;
req.request:请求方法;
req.url:请求的url;
req.proto:请求的http协议版本;
req.backend:用于服务此次请求的后端主机;
req.backend.healthy:后端主机的健康状态;
req.http.HEADER:引用请求报文中指定的首部;
req.can_gzip:客户端是否能够接受gzip压缩格式的响应内容;
req.restarts:此请求被重启的次数;
3、varnish向backend主机发起请求前可用的变量(图示2)
bereq.request:请求方法;
bereq.url:
bereq.proto:
bereq.http.HEADER
bereq.connect_timeout: 等待与backend建立连接的超时时长;
4、backend响应报文到达varnish后,放置于cache中之前可用的变量(图示3之后4之前)
beresp.do_stream:流式响应;
beresp.do_gzip:是否压缩之后再存入缓存;
beresp.do_gunzip:是否解压后再存入缓存;
beresp.http.HEADER:
beresp.proto:
beresp.status:响应状态码;
beresp.response:响应时的原因短语;
beresp.ttl:响应对象剩余的生存时长,单位为second,此值可自定义修改;
beresp.backend.name:此响应报文来源backend名称;
beresp.backend.ip
beresp..backend.port
beresp.storage:将响应报文存储在指定的存储后端
5、缓存对象存入cache之后可用的变量(图示4)
obj.proto
obj.status:响应状态码;
obj.response:响应时的原因短语;obj.ttl
obj.hits:缓存对象命中次数;
obj.http.HEADER
6、在决定对请求键作hash计算时可用的变量
req.hash:以指定查询缓存的键做为hash计算的键;
7、在为客户端构建响应报文时可用的变量(图示5)
resp.proto
resp.status
resp.response
resp.http.HEADER
wKioL1Vy4FOhimIoAAD2BwXp3ow120.jpg
变量适用位置及相应权限表
wKioL1Vy4GrBCimeAAE1pg7Pi0w569.jpg
Varnish检测后端主机的健康状态
Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判,Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。
每个后端服务器当前探测的健康状态探测方法通过.probe进行设定,其结果可由req.backend.healthy变量获取,也可通过varnishlog中的Backend_health查看或varnishadm的debug.health查看。
backendweb1 {
.host = "www.zrcj.com";
.probe= {
.url= "/.healthtest.html";
.interval= 1s;
.window= 5;
.threshold= 2;
}
}
.probe中的探测指令常用的有:
(1).url:
探测后端主机健康状态时请求的URL,默认为“/”;
(2).request:
探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:
.request=
"GET /.healthtest.html HTTP/1.1"//使用1.1版本“GET”方法请求健康状态检测页面
"Host: www.zrcj.com" //请求的主机名
"Connection: close";//不使用“keepalive”长连接
(3).window:
设定采样范围,在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;
(4).threshold:
设定阈值,在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;
(5).initial:
Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;
(6).expected_response:
期望后端主机响应的状态码,一般与“.url”或“.request”结合使用,默认为200;
(7).interval:
探测请求的发送周期,默认为5秒;
(8).timeout:
每次探测请求的过期时长,默认为2秒;
Varnish调度多台后端主机
Varnish中可以使用director指令将一个或多个近似的后端主机定义为一个逻辑组,并能以指定的调度方式来轮流将请求发送至这些主机上。不同的director可以使用同一个后端主机,而某director也可以使用“匿名”后端主机(在director中直接进行定义)。每个director都必须有其专用名,且在定义后必须在VCL中进行调用,VCL中任何可以指定后端主机的位置均可以按需将其替换为调用某已定义的director。
定义格式
backendweb1 {
.host= "backweb1.magedu.com";
.port= "80";
}
directorwebservers random {
.retries= 5;
{
.backend= web1;
.weight  = 2;
}
{
.backend  = {
.host= "backweb2.magedu.com";
.port= "80";
}
.weight= 3;
}
}
如上示例中,web1为显式定义的后端主机,而webservers这个director还包含了一个“匿名”后端主机(backweb2.magedu.com)。webservers从这两个后端主机中挑选一个主机的方法为random,即以随机方式挑选。
director调度算法
Varnish的director支持的挑选方法中比较简单的有round-robin和random两种。其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,挑选方式为“轮叫”,并在某后端主机故障时不再将其视作挑选对象;random方法随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数以指定其权重,同时还可以director级别使用.retries参数来设定查找一个健康后端主机时的尝试次数。
Varnish2.1.0后,random挑选方法又多了两种变化形式client和hash。client类型的director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机。client.identity默认为client.ip,但也可以在VCL中将其修改为所需要的标识符。类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。
fallback定义备用服务器
directorb3 fallback {
  { .backend = www1; }
  { .backend = www2; } //will only be used if www1 is unhealthy.
  { .backend = www3; } //will only be used if both www1 and www2
}                      // are unhealthy.
范文示例
HTTP/1.1“Cache-Control”首部示例
Cache-Control   = "Cache-Control" ":"1#cache-directive
    cache-directive = cache-request-directive
         | cache-response-directive
    cache-request-directive =
           "no-cache"                        
         | "no-store" (backup)                        
         | "max-age" "="delta-seconds        
         | "max-stale" ["=" delta-seconds ]
         | "min-fresh" "="delta-seconds     
         | "no-transform"                     
         | "only-if-cached"                  
         | cache-extension   
     cache-response-directive =
           "public"                              
         | "private" [ "="<"> 1#field-name <"> ]
         | "no-cache" [ "="<"> 1#field-name <"> ]
         | "no-store"                           
         | "no-transform"                        
         | "must-revalidate"                    
         | "proxy-revalidate"                  
         | "max-age" "="delta-seconds           
         | "s-maxage" "="delta-seconds         
         | cache-extension
默认常规设置
sub vcl_recv {
1、设置请求报文首部,使后端主机的日志能记录请求的真正客户端来源
     if (req.restarts == 0) {
        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;
        }
    }
2、设置拒绝指定来源的主机访问
     if (client.ip =="172.16.250.133") {
       error 404 "Not Found";
     }
3、设置无法识别的请求方法直接送给后端主机处理
     if (req.request != "GET"&&
       req.request != "HEAD"&&
       req.request != "PUT"&&
       req.request != "POST"&&
       req.request != "TRACE"&&
       req.request != "OPTIONS"&&
       req.request != "DELETE") {
         /* Non-RFC2616 or CONNECT which isweird. */
         return (pipe);
     }
4、设置可以创建缓存的请求方法
     if (req.request != "GET"&& req.request != "HEAD") {
         /* We only deal with GET and HEAD bydefault */
         return (pass);
     }
     if (req.http.Authorization ||req.http.Cookie) {
         /* Not cacheable by default */
         return (pass);
     }
     return (lookup);
}
使“设置1”生效的方法:
修改后端主机的http日志记录格式
#vim /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\"\"%{User-Agent}i\"" combined
查看后端主机日志记录
#tail /var/log/httpd/access_log
wKioL1Vy4N6QPbQFAAFoFpqqdvQ288.jpg
显示修改已然生效
设置以指定主机响应指定访问
subvcl_recv {
  if (req.http.host ~ "(?i)^(www.)?magedu.com$") {
    set req.http.host = "www.magedu.com";
    set req.backend = www;//若访问www.magedu.com,以www主机响应
  } elsif (req.http.host ~"(?i)^images.magedu.com$") {
   set req.backend = images;//若访问images.magedu.com,以images主机响应
  } else {
   error 404 "Unknown virtual host";//非以上两种访问请求,响应404错误
  }
}
移除单个缓存对象
purge用于清理缓存中的某特定对象及其变种(variants),因此,在有着明确要修剪的缓存对象时可以使用此种方式。HTTP协议的PURGE方法可以实现purge功能,不过,其仅能用于vcl_hit和vcl_miss中,它会释放内存工作并移除指定缓存对象的所有Vary:-变种,并等待下一个针对此内容的客户端请求到达时刷新此内容。另外,其一般要与return(restart)一起使用。下面是个在VCL中配置的示例。
aclpurgers {
"127.0.0.1";
"172.16.0.0"/16;
}//指明允许发起“purge”操作的主机
subvcl_recv {
if(req.request == "PURGE") {
if(!client.ip ~ purgers) {
error405 "Method not allowed";
}
return(lookup);
}
}//非允许的主机发起的“purge”请求被返回错误提示,允许的继续查缓存
subvcl_hit {
if(req.request == "PURGE") {
purge;
error200 "Purged";
}
}//缓存名字,则删除此缓存,并返回“成功,已删除”;
subvcl_miss {
if(req.request == "PURGE") {
purge;
error404 "Not in cache";
}
}//缓存未命中,则返回“404错误,无此缓存”
subvcl_pass {
if(req.request == "PURGE") {
error502 "PURGE on a passed object";
}
}//“purge”发错engine,则返回“502错误,发送错误”
wKioL1Vy4WrT38TDAANa2nJxucc943.jpg
wKiom1Vy38yxmGFAAAFttYBK24s063.jpg

客户端在发起HTTP请求时,只需要为所请求的URL使用PURGE方法即可,其命令使用方式如下:
# curl -I -X PURGE http://varniship/path/to/someurl
注意:若要使用此设置,必须在可接受的请求方法和可缓存的请求方法中加入“PURGE”方法;
设置健康状态检测机制
probechk {
.url= "/index.html";
.window= 5;
.threshold= 3;
.interval= 3s;
.timeout= 1s;
}
backendappserv {
.host= "172.16.14.2";
.port= "80";
.probe= chk;
}
backendstatic {
.host= "172.16.14.3";
.port= "80";
.probe= chk;
}
两后端主机起始状态
wKiom1Vy4AeAYtvQAAG4BqR6scg400.jpg
移除appserv的/index.html文件后
wKioL1Vy4dqSXIhTAAGWlJkkUz8197.jpg
移回appserv的/index.html文件后
wKiom1Vy4EqDkGozAAGLYlDCtV8433.jpg


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-74855-1-1.html 上篇帖子: HAProxy的三种不同类型配置方案 下篇帖子: HAProxy配置文件详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表