varnish页面缓存代理服务详解

一、Web缓存

1.web缓存

web缓存是可以自动保存常见文档副本的HTTP设备。当Web请求抵达缓存时,如果本地有"已缓存的"副本,可以从本地的存储设备而不是原始服务器设备中提取这个文档。

通过key-value键值方式缓存,key中保存了URL路径,value中保存了web内容,其均使用hash格式,算法保证能在海量数据中快速命中缓存内容

(1)缓存优点

1) 减少冗余的数据传输,节省带宽

2) 缓解网络瓶颈问题,无需耕宇宽带就能更快的加载页面

3) 降低对原始服务器的要求,服务器可以更快的响应避免过载

4) 降低了距离时延

(2)相关术语


缓存命中


cache hit,可以用已有的副本为某些到达缓存的请求提供服务


缓存未命中


cache miss,无缓存命中副本,被转向后端原始服务器


HTTP再验证


revalidation,新鲜度检测,缓存副本和原始服务器上的数据要不时的进行检测是否为最新


命中率


cache hit rate,缓存提供服务的请求所占的比例,命中率在0-1之间,通常用百分数描述

注意:

1) 命中率可以分为:文档命中率(从文档个数进行衡量)、字节命中率(从内容大小进行衡量)

2) 缓存对象由其生命周期,需要定期清理

3)当缓存空间耗尽,会采用LRU(最近最少使用算法)进行覆盖

4)不是所有的数据都能够缓存,如首部Authorization、Cookie、Vary:accept-encoding=  … ...

(3)缓存处理的步骤:

接收请求 -->解析请求(提取请求的URL及各种首部) --> 查询缓存 --> 新鲜度检测 --> 创建响应报文--> 发送响应 --> 记录日志

2.HTTP首部缓存控制机制

Cache-Control: no-store禁止缓存对响应进行复制

Cache-Control: no-cache可以存储在本地缓存区域中,只是在于原始服务器进行新鲜度在验证之前缓存不能提供给客户端使用

Cache-Control:must-revalidate严格遵循过期信息,在实现没和服务器再验证不提供对象旧的副本。新鲜度检测失败返回504

Cache-Control: max-age读秒,仅适用于公共缓存

Expries日期首部到响应中,指明具体时间,不推荐使用

不添加过期信息,让缓存确定自己的过期日期

(1)新鲜度检测机制

在HTTP协议的报文首部会对web作出首部定义,通过首部的报文对比来做新鲜度检测。HTTP/1.0 Expires定义的是绝对时间,当达到指定的日期时间的时候,缓存失效;HTTP/1.1 Cache-Control:max-age=#定义的是相对时间,记秒,已解决HTTP/1.0协议在解决全球性数据缓存检测时各地区时差产生的问题

实例:

HTTP/1.0 Expires:Thu, 04 Jun 2015 23:38:18 GMT

HTTP/1.1Cache-Control:max-age=600

(2)有效性再验正:revalidate

如果原始内容未改变,则仅响应首部(不附带body部分),响应码304(Not Modified)

如果原始内容发生改变,则正常响应,响应码200;

如果原始内容消失,则响应404,此时缓存中的cacheobject也应该被删除;

说明:

相关条件式请求首部:If-Modified-Since、If-Unmodified-Since、If-Match、If-None-Match:


If-Modified-Sicce:<date>


如果从指定日期之后文档被修改了,就执行请求的方法。可以与Last-Modified(最后被修改)服务器响应首部配合使用,只有在内容被修改后与已缓存版本有所不同时候采取获取内容


If-None_Match:<tags>


标签,如果一缓存标签与服务器文档中的标签不同,If-None_Match首部就会执行请求的方法

HTTP缓存报文实例:

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

3.常见的缓存服务开源解决方案


软件


存储模式


性能


配置复杂度


purge效率


共享存储


squid


硬盘


较高


简单



可以并联,但是配置复杂


varnish


硬盘/内存



比较简单



不能

说明:

Squid,很古老的反向代理软件,拥有传统代理、身份验证、流量管理等高级功能,但是配置太复杂。优势在于完整的庞大的cache技术资料。Squid在大规模负载均衡场景下很稳定

Varnish是新兴的一个软件,设计简单,基于内存缓存,重启后数据将消失。

(1)varnish对比squid的优点

1)varnish稳定性很高,两者在完成相同负荷的工作时,squid服务器发生故障的几率要高于varnish,因为squid要经常重启

2)varnish访问速度更快,其采用了"Visual PageCache"技术,所有缓存数据都直接从内存中读取,而squid是从硬盘读取,因而varnish在访问速度方面会更快

3)varnish可支持更多并发连接,因为varnish的TCP连接释放要比squid快,因而在高并发连接情况下可以支持更多TCP连接

4)varnish可以通过管理端口,使用正则表达式批量的清除部分缓存,而squid是做不到的。

5)squid属于单进程使用单核CPU,但Varnish是通过fork形式打开多进程来做处理,所以是合理的使用所有核来处理相应的请求

(2)varnish对比squid的缺点

1)varnish进程一旦Hang、Crash或者重启,缓存数据都会从内存中完全释放,此时所有请求都会发送到后端服务器,在高并发情况下,会给后端服务器造成很大的压力

2)在varnish使用中,如果单个vrl的请求通过HA/F5,每次请求不同的varnish服务器时,被请求的varnish服务器都会被穿透到后端,而同样的请求会在多台服务器上缓存,也会造成varnish的缓存资源浪费,也会造成性能下降

二、Varnish缓存概述

1.varnish程序架构

varnish是高性能开源反向代理服务器,http加速器。官方网址:www.varnish-cache.org。版本:v2,v3,v4

架构图:

主要运行两个进程:Management进程和Child(Cache)进程

(1) Management管理进程

主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会定期探测Child进程。若在指定时长未得到Child进程回应,会重启此Child进程。

配置文件是VCL编程语言格式,定义缓存工作功能的,VCL编译器需要调用C编译器编译后成varnish能加载的格式才能使用

(2) Child(Cache)进程

Child进程包含多种类型的线程,主要用于用户请求管理和缓存管理

Acceptor:接收器,接收新的连接请求并响应;

Worker:处理用户请求

Expiry:从缓存中清理过期缓存内容;

cache-worker线程

cache-main线程:此线程只有一个,用于启动caceh;

ban luker:缓存清理线程

acceptor:接收线程

epoll:线程池管理器

expire:清理过期缓存

注意:

Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session工作区。

(3) VCL和C编译器

VCL编写的缓存策略保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。

VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。

(4) 调用接口

CLIInterface(命令行接口)、telent Interface(文本协议不安全)、web Interface(商业)

(5) varnish log file日志

1) 共享内存日志(shared memory log):日志保存在内存中的共享空间,大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁

2) varnish log在内存中实现日志保存,默认不能长久保存,会循环保存

3) varnish提供多个工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并以指定的方式进行显示。

2.VCL:配置缓存策略工具

Varnish Configuration Language (VCL):

(1)基于“域”(domain specific)的简单编程语言

(2)支持有限的算术运算和逻辑运算操作

(3)允许使用正则表达式进行字符串匹配

(4)允许用户使用set自定义变量

(5)支持if判断语句

(6)支持内置的函数和变量等。

3.varnish存储类型

(1)file:单个文件;不支持持久机制

使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域

(2)malloc:内存方式

使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;

(3)persistent(experimental):基于文件的持久存储

与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;

注意:

1) file存储方法在varnish停止或重启时会清除数据:varnish无法追踪某缓存对象是否存入了缓存文件

2) persistent仅适用于有巨大缓存空间的场景,目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,

3) 建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。

4) 对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。

三、安装启动varnish服务

1.安装相关程序包

[[email protected] ~]#yum install -y  gcc  varnish-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpmvarnish-libs-3.0.4-1.el6.x86_64.rpm varnish-libs-devel-3.0.4-1.el6.x86_64.rpm

说明:

1) gcc编辑器是varnish编译val语言所需的依赖组件

2) varnish提供程序的主包、varnish-libs提供程序相关的库,必须安装

3) varnish-libs-devel提供二次开发所依赖的库文件、varnish-docs提供varnish帮助文档,可以视情况安装

2.配置varnish启动时脚本配置文件/etc/sysconfig/varnish

[[email protected] ~]# vim /etc/sysconfig/varnish


NFILES=131072


打开的最大文件数


MEMLOCK=82000


锁定共享内存大小


NPROCS="unlimited"


最大线程数,无限制


RELOAD_VCL=1


自动重新装载缓存策略,1表示脚本启动自动重新装载缓存策略配置文件


VARNISH_VCL_CONF=/etc/varnish/default.vcl


默认的缓存策略配置文件


VARNISH_LISTEN_PORT=6081


默认监听端口,一般改为80端口


VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1


管理员management进程管理地址


VARNISH_ADMIN_LISTEN_PORT=6082


管理员management进程管理端口


VARNISH_SECRET_FILE=/etc/varnish/secret


启动装载的密钥文件位置,域共享密钥


VARNISH_MIN_THREADS=50


最少线程,启动时最骚启动的空闲进程


VARNISH_MAX_THREADS=1000


最大启动进程,最多不能超过5000个并发


VARNISH_THREAD_TIMEOUT=120


线程超时时长


VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin


缓存文件存放文件(二进制文件)


VARNISH_STORAGE_SIZE=1G


缓存大小


VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"


缓存类型和大小


VARNISH_TTL=120


当后端主机不是指定的时候使用超时时长


DAEMON_OPTS="-a  ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \

-f ${VARNISH_VCL_CONF} \

-T  ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \

-t ${VARNISH_TTL} \

-w  ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \

-u varnish -g varnish \

-S ${VARNISH_SECRET_FILE} \

-s ${VARNISH_STORAGE}"

注意:

以下配置必须修改:VARNISH_LISTEN_PORT=80,一般改为80端口,响应http请求,做为web缓存

VARNISH_STORAGE,一般在大规模图片缓存时候可以为file,但时硬件上最好是固态硬盘

3.启动服务

[[email protected]~]# service varnish start

四、varnish命令行管理工具

1.varnishadm:登录命令行终端

命令语法:varnishadm[-t timeout] [-S secret_file] [-T address:port] [-n name] [command [...]]

[[email protected]~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082

varnish> help


vcl.list


查看配置文件


vcl.load


重新编译加载vcl配置,需要指明自定义版本名称,和需要编译的文件default.vcl位置(相对)


vcl.use


使用编译的配置文件,指明自定义版本名称


vcl.show


显示指定的配置文件详细信息,指明自定义版本名称


vcl.discard


手动清理版本,否则旧版本配置信息会在varnish重启后丢弃

2.varnish的param(参数)查看及设置

param.show[-l] [param]

param.set[param] [value]

varnish通过线程池模型定义其最大并发连接数:


thread_pools


线程池个数;默认为2;


thread_pool_max


单个线程池内允许启动的最多线程个数;


thread_pool_min


启动时要启动的线程数;


thread_pool_purge_delay


清理线程的时间长度,最小不能100毫秒


thread_pool_stack


工作线程栈,默认为-1,unlimited,不做限制


thread_pool_timeout


超时时长,多于thread_pool_min的线程空闲此参数指定的时长后即被purge


thread_pool_wokerspace


工作空间,默认使用内存65536字节

3.varnishtop: 内存日志区域查看工具

-Iregexp: 仅显示被模式匹配到的条目

-Xregexp:仅显示不被模式匹配到的条目

-C:忽略字符大小写;

-d:显示已有日志;

varnish>varnishtopUser-Agent

显示结果实例:

RxHeader User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/43.0.2357.81 Safari/537.36

说明:

RxHeader:称为tag,基于tag过滤,可使用-i或-x选项;

User-Agent起始的内容:称为日志信息,可使用-I或-X选项进行过滤;

4.varnishstat:varnish数据统计工具

-f field, field, …:指明显示的字段

-l:列出所有可用字段

-x:xml输出格式

-j:json输出格式

五、VCL状态引擎制定缓存策略

1.varnish状态引擎

varnish内部有几个所谓的状态(state),在这些状态上可以附加通过VCL定义的策略以完成相应的缓存处理机制,因此VCL也经常被称作“域专用”语言或状态引擎,“域专用”指的是有些数据仅出现于特定的状态中。

状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并指示varnish进入下一个状态。

(1)状态引擎分类

vcl_recv、vcl_hash、vcl_hit、vcl_miss、vcl_fetch、vcl_deliver、vcl_pipe、vcl_pass、vcl_error


vcl_init


在装载vcl,用其处理任何请求之前


vcl_recv


请求被接入,但在其被分析、处理完成之前;是否服务此请求、如何服务、使用哪个后端主机为其服务


vcl_pipe


方法不理解


vcl_pass


不查询缓存


vcl_hash


查找缓存,调用内置hash_data()函数,决定对什么内容hash计算,如后端存在虚拟主机,但用ip访问不能命中


vcl_hit


命中


vcl_miss


未命中


vcl_fetch


在后端服务器取内容,其能让可缓存或不缓存。从后端主机收到响应报文之前会被调用,返回的值可以为deliver、error  code [reason]、hit_for_pass、restart


vcl_deliver


传送


vcl_error


错误处理机制

(2)状态引擎工作流程(v3):

varnish先对HTTP请求本身进本分析,再由vcl_recv方法完成决策(是否在缓存中查询请求额资源)

vcl_recv--> vcl_hash --> vcl_hit --> vcl_deliver

vcl_recv--> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver

vcl_recv--> vcl_pass --> vcl_fetch --> vcl_deliver

vcl_recv--> vcl_pipe

(3)vcl_recv引擎

vcl_recv是在Varnish完成对请求报文的解码为基本数据结构后第一个要执行的子例程,它通常有四个主要用途:

1)修改客户端数据以减少缓存对象差异性;比如删除URL中的www.等字符;

2)基于客户端数据选用缓存策略;比如仅缓存特定的URL请求、不缓存POST请求等;

3)为某web应用程序执行URL重写规则;

4)挑选合适的后端Web服务器;

可以通过return()向Varnish返回的指示操作:

pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

pipe:不对客户端进行检查或做出任何操作,而是在客户端与后端服务器之间建立专用“管道”,并直接将数据在二者之间进行传送;此时,keep-alive连接中后续传送的数据也都将通过此管道进行直接传送,并不会出现在任何日志中;

lookup:在缓存中查找用户请求的对象,如果缓存中没有其请求的对象,后续操作很可能会将其请求的对象进行缓存;

error:由Varnish自己合成一个响应报文,一般是响应一个错误类信息、重定向类信息或负载均衡器返回的后端web服务器健康状态检查类信息;

注意:

1) Varnish默认的vcl_recv专门设计用来实现安全的缓存策略,它主要完成两种功能:

a)仅处理可以识别的HTTP方法,并且只缓存GET和HEAD方法;

b)不缓存任何用户特有的数据;

2) 一般自定义vcl_recv中不要使用return()终止语句,而是再由默认vcl_recv进行处理,并由其做出相应的处理决策。

#sub vcl_recv {

#     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;

#        }

#     }

#     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);

#     }

#     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);

#}

(3)vcl_fetch引擎

vcl_fetch是根据服务器端的响应作出缓存决策。在任何VCL状态引擎中返回pass操作都将由vcl_fetch进行后续处理。默认的vcl_fetch放弃了缓存任何使用了Set-Cookie首部的响应。通过return()返回给varnish的操作指示有:

1)deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver);

2)hit_for_pass:不缓存此对象,但可以导致后续对此对象的请求直接送达到vcl_pass进行处理;

3)restart:重启整个VCL,并增加重启计数;超出max_restarts限定的最大重启次数后将会返回错误信息;

4)errorcode [reason]:返回指定的错误代码给客户端并丢弃此请求;

2.VCL编程语言语法

(1) //, #, /* */用于注释;会被编译器忽略;

(2) sub $name定义函数,不接受参数;VCL内部的数据传递只能隐藏在HTTP首部内部进行

(3) 不支持循环语句;

(4)有众多内置的变量,变量的可调用位置与state engine有密切相关性;

(5)支持终止语句,return(action);没有返回值;

(6) "域"专用语言,只能用在特定的域上;

(7) 支持众多操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)

(8) 一般为条件判断语句:单分支、双分支、多分支

3.varnish内置函数

(1)regsub(str,regex,sub)

regsuball(str,regex,sub):这两个用于基于正则表达式搜索指定的字符串并将其替换为指定的字符串;但regsuball()可以将str中能够被regex匹配到的字符串统统替换为sub,regsub()只替换一次;

(2)ban(expression):

ban_url(regex):Bans所有其URL能够由regex匹配的缓存对象;

(3)purge:

从缓存中挑选出某对象以及其相关变种一并删除,这可以通过HTTP协议的PURGE方法完成;

(4)hash_data(str):

return():当某VCL域运行结束时将控制权返回给Varnish,并指示Varnish如何进行后续的动作;其可以返回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等;但某特定域可能仅能返回某些特定的指令

return(restart)重新运行整个VCL,即重新从vcl_recv开始进行处理;每一次重启都会增加req.restarts变量中的值,而max_restarts参数则用于限定最大重启次数。

4.常用变量

(1)在任何状态引擎中均可

.host后端主机的主机名或者IP

.port后端主机的服务名或者端口号

(2)用于处理请求阶段

client.ip客户端ip

server.hostname缓存服务器主机名

server.ip缓存服务器ip

server.port缓存服务器端口

req.request:请求方法

req.url:请求的URL

req.proto:请求的HTTP协议版本

req.backend:指定用于服务此次请求的后端主机

req.backend.healthy:后端主机的健康状态

req.http.HEADER:调用request报文中http协议的指定的HEADER首部

req.can_gzip:客户端是否能结束gzip压缩格式响应内容

req.restarts:此请求被重启的次数

req.grace:宽限期响应

(3)varnish向backend主机发起请求前可用的变量

bereq.request:后端主机请求方法

bereq.url:后端主机请求路径

bereq.proto:后端主机请求http协议

bereq.http.HEADER:后端主机HTTP首部

bereq.connect.timeout:等待后端建立连接的超时时长

(4)backend主机的响应报文到达本主机(varnish)后,将其放置在cache中之前可用的变量

beresp.do_stream:流式响应(接收一个响应一个)

beresp.do_gzip:是否压缩后存储

beresp.do_gunzip:是否先解压缩再存储

beresp.http.HEADER:后端主机响应http首部

beresp.proto:后端主机响应http协议

beresp.status:后端主机响应状态码

beresp.response:响应的原因短语

beresp.ttl:响应对象剩余的响应时长,单位为秒

beresp.backend.name指明此响应报文来源的后端主机的名称

beresp.backend.ip指明此响应报文来源的后端主机的ip地址

beresp.backend.port指明此响应报文来源的后端主机的端口号

beresp.storage强制varnish存储在指定的缓存后端

(5)缓存对象(从后端主机取出内容)存入cache之后可用变量

obj.proto:缓存对象响应时的协议

obj.status:缓存对象响应时的状态码

obj.response:缓存对象响应时的原因短语

obj.ttl:缓存对象响应时的生存时长

obj.hits:缓存对象响应时的命中次数

obj.http.HEADER:缓存对象响应时的的http首部

(6)在决定对请求的键做hash计算时可用变量

req.hash:指明将什么键当成hash缓存的键

(7)在为客户端准备响应报文时可用的变量

resp.proto响应的协议

resp.status响应的状态码

resp.response响应的响应原因短语

resp.http.HEADER响应的

变量的可用位置:

官方文档:https://www.varnish-cache.org/docs/4.0/reference/vcl.html#varnish-configuration-language

5.使用案例概述

(1)变量赋值:set name=value

实例:定义在vcl_deliver中,向响应给客户端的报文添加一个自定义首部X-Cache;

if (obj.hits>0) {

set resp.http.X-Cache ="HIT";

} else {

set resp.http.X-Cahce ="MISS";

}

(2)支持虚拟主机:

if(req.http.host == "www.magedu.com"){

}

(3)强制对某资源的请求,不检查缓存;

实例:对URL以/admin和/login结尾不做缓存:

if(req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {

return(pass);

}

(4)对特定类型的资源取消其私有的cookie标识,并强行设定其可以varnish缓存的时长:

vcl_backend_response

if(beresp.http.cache-control !~ "s-maxage") {

if(bereq.url ~ "(?i)\.jpg$") {

setberesp.ttl = 3600s;

unsetberesp.http.Set-Cookie;

}

if(bereq.url ~ "(?i)\.css$") {

setberesp.ttl = 600s;

unsetberesp.http.Set-Cookie;

}

}

官方配置示例:https://www.varnish-cache.org/trac/wiki/VCLExamples

六、varnish后端主机健康监测和负载均衡

1.backend server的定义

backend name {

.attribute ="value";

}


.host


后端主机的IP;


.port


后端主机监听的PORT;


.probe


对后端做健康状态检测;


.max_connections


并连接最大数量;

2.后端主机的健康状态检测方式

probe name {

.attribute= "value";

}


.url:


判定BE健康与否要请求的url;


.expected_response


期望响应状态码;默认为200;

实例一:

backendwebsrv1 {

.host = "172.16.100.68";

.port = "80";

.probe = {

.url = "/test1.html";

}

}

backendwebsrv2 {

.host = "172.16.100.69";

.port = "80";

.probe = {

.url = "/test1.html";

}

}

subvcl_recv {

if (req.url ~"(?i)\.(jpg|png|gif)$") {

set req.backend_hint = websrv1;

} else {

set req.backend_hint = websrv2;

}

}

实例二:

importdirectors;

subvcl_init {

new mycluster = directors.round_robin();

mycluster.add_backend(websrv1);

mycluster.add_backend(websrv2);

}

vcl_recv{

setreq.backend_hint = mycluster.backend();

}

负载均衡算法:fallback,random, round_robin, hash

七、实际案例

1.移除单个缓存对象

purge用于清理缓存中的某特定对象及其变种(variants),因此,在有着明确要修剪的缓存对象时可以使用此种方式。HTTP协议的PURGE方法可以实现purge功能,不过,其仅能用于vcl_hit和vcl_miss中,它会释放内存工作并移除指定缓存对象的所有Vary:-变种,并等待下一个针对此内容的客户端请求到达时刷新此内容。另外,其一般要与return(restart)一起使用。下面是个在VCL中配置的示例。

aclpurgers {

"127.0.0.1";

"192.168.0.0"/24;

}

subvcl_recv {

if(req.request == "PURGE") {

if(!client.ip ~ purgers) {

error405 "Method not allowed";

}

return(lookup);

}

}

subvcl_hit {

if(req.request == "PURGE") {

purge;

error200 "Purged";

}

}

subvcl_miss {

if(req.request == "PURGE") {

purge;

error404 "Not in cache";

}

}

subvcl_pass {

if(req.request == "PURGE") {

error502 "PURGE on a passed object";

}

}

客户端在发起HTTP请求时,只需要为所请求的URL使用PURGE方法即可,其命令使用方式如下:

#curl -I -X PURGE http://varniship/path/to/someurl

2.生产环境案例实例

aclpurge {

"localhost";

"127.0.0.1";

"10.1.0.0"/16;

"192.168.0.0"/16;

}

subvcl_hash {

hash_data(req.url);

return (hash);

}

subvcl_recv {

set req.backend = shopweb;

#  set req.grace = 4h;

if (req.request == "PURGE") {

if (!client.ip ~ purge) {

error 405 "Not allowed.";

}

return(lookup);

}

if (req.request == "REPURGE") {

if (!client.ip ~ purge) {

error 405 "Not allowed.";

}

ban("req.http.host == " +req.http.host + " && req.url ~ " + req.url);

error 200 "Ban OK";

}

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;

}

}

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 is weird.*/

return (pipe);

}

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

/* We only deal with GET and HEAD bydefault */

return (pass);

}

if (req.http.Authorization) {

/* Not cacheable by default */

return (pass);

}

if ( req.url == "/Heartbeat.html" ){

return (pipe);

}

if ( req.url == "/" ) {

return (pipe);

}

if ( req.url == "/index.jsp" ) {

return (pipe);

}

if (req.http.Cookie ~ "dper=") {

return (pass);

}

if (req.http.Cookie ~ "sqltrace="){

return (pass);

}

if (req.http.Cookie ~"errortrace=") {

return (pass);

}

#   if ( req.request == "GET"&& req.url ~ "req.url ~ "^/shop/[0-9]+$" ) {

if ( req.url ~ "^/shop/[0-9]+$" ||req.url ~ "^/shop/[0-9]?.*" ) {

return (lookup);

}

if ( req.url ~"^/shop/(\d{1,})/editmember" || req.url ~"^/shop/(\d{1,})/map" || req.url ~"^/shop/(\d+)/dish-([^/]+)" ) {

return (lookup);

}

return (pass);

#   return (lookup);

}

subvcl_pipe {

return (pipe);

}

subvcl_pass {

return (pass);

}

subvcl_hit {

if (req.request == "PURGE") {

purge;

error 200 "Purged.";

}

return (deliver);

}

subvcl_miss {

if (req.request == "PURGE") {

error 404 "Not in cache.";

}

#   if (object needs ESI processing) {

#     unset bereq.http.accept-encoding;

#   }

return (fetch);

}

subvcl_fetch {

set beresp.ttl = 3600s;

set beresp.http.expires = beresp.ttl;

#set beresp.grace = 4h;

#   if (object needs ESI processing) {

#     set beresp.do_esi = true;

#     set beresp.do_gzip = true;

#   }

if ( req.url ~ "^/shop/[0-9]+$" ||req.url ~ "^/shop/[0-9]?.*" ) {

set beresp.ttl = 4h;

}

if ( req.url ~"^/shop/(\d{1,})/editmember" || req.url ~"^/shop/(\d{1,})/map" || req.url ~"^/shop/(\d+)/dish-([^/]+)" ) {

set beresp.ttl = 24h;

}

if (beresp.status != 200){

return (hit_for_pass);

}

return (deliver);

}

subvcl_deliver {

if (obj.hits > 0){

set resp.http.X-Cache = "HIT";

}

else {

set resp.http.X-Cache = "MISS";

}

set resp.http.X-Powered-By = "Cache on" + server.ip;

set resp.http.X-Age = resp.http.Age;

return (deliver);

}

subvcl_error {

set obj.http.Content-Type = "text/html;charset=utf-8";

set obj.http.Retry-After = "5";

synthetic {""} + obj.status +" " + obj.response + {""};

return (deliver);

}

subvcl_init {

return (ok);

}

subvcl_fini {

return (ok);

}

时间: 2024-10-07 17:43:10

varnish页面缓存代理服务详解的相关文章

varnish安装及配置详解

varnish系统架构: varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程). Management进程主要实现应用新的配置.编译VCL.监控varnish.初始化varnish以及提供一个命令行接口等.Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程. Child进程包含多种类型的线程,常见的如:Acceptor线程:接收新的连接

浏览器缓存机制详解

对于浏览器缓存,相信很多开发者对它真的是又爱又恨.一方面极大地提升了用户体验,而另一方面有时会因为读取了缓存而展示了"错误"的东西,而在开发过程中千方百计地想把缓存禁掉.那么浏览器缓存究竟是个什么样的神奇玩意呢? 什么是浏览器缓存: 简单来说,浏览器缓存就是把一个已经请求过的Web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中.缓存会根据进来的请求保存输出内容的副本.当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是

浏览器 HTTP 协议缓存机制详解

1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Refer: https://www.cnblogs.com/520yang/articles/4807408.html 最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里

Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图片加载框架,介绍的是图片缓存策略方面的,如果大家对这个开源框架的使用还不了解,大家可以看看我之前写的一篇文章Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用,我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,我之前也写了几篇异步加载大量图片的文章,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近

Hibernate 所有缓存机制详解

Hibernate 所有缓存机制详解 hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了. hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存.如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了. 缓存和连接池的区别:缓存和池都是放在内存里,实现是一样的

Redis for Windows(C#缓存)配置文件详解

Redis for Windows(C#缓存)配置文件详解 前言 在上一篇文章中主要介绍了Redis在Windows平台下的下载安装和简单使用http://www.cnblogs.com/aehyok/p/3478282.html.当然我也在上一篇中指定过配置文件,并且修改其中的端口port.本文将主要来探讨redis强大的配置文件. 我现在使用的redis版本为2.6.首先奉上配置文件的源文件. # Redis configuration file example # Note on unit

网站页面静态化详解

URL静态化 静态化一直以来都是最基本的seo要求之一,但近一两年seo行业对是否一定要做静态化有了一些观念上的改变. 为什么静态化 现在的网站绝大多数是数据库驱动,页面由程序实时生成,而不是其的在服务器上有一个静态html文件存在.当用户访问一个网址时,程序根据url中的参数调用数据库数据,实时生成页面内容.因此动态页面相对应的url原始状态也是动态的,包含问号.等号及参数,如下面这种典型论坛的url: 3w点website点com/viewthread.php?tid=1234&&pa

《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项

<深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面   MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓存机制上.MyBatis提供了一级缓存.二级缓存 这两个缓存机制,能够很好地处理和维护缓存,以提高系统的性能.本文的目的则是向读者详细介绍MyBatis的一级缓存,深入源码,解析MyBatis一级缓存的实现原理,并且针对一级缓存的特点提出了在实际使用过程中应该注意的事项. 读完本文,你将会学到: 1.什么是一

.Net 缓存依赖详解

缓存命名空间的讲解流程 16.1  System.Web.Caching简介 本节从缓存命名空间的总体简介和组成结构入手,从整体上对System.Web.Caching进行概述. 16.1.1  System.Web.Caching概述 System.Web.Caching 是用来管理缓存的命名空间.缓存就是将服务器端的数据暂时保存在客户端,方便用户的读取.缓存命名空间的父级空间是“System.Web”,由此可以看 出,缓存通常用于Web网站的开发,包括在B/S项目中的开发.缓存的设计主要是考