前文咱们聊了下varnish的VCL配置以及语法特色,怎样去编译加载varnish的vcl配置,以及命令行管理工具varnishadm怎么去链接varnish管理接口进行管理varnish,回顾请参考http://www.javashuo.com/article/p-kurdszjv-mk.html;今天咱们来讲一下varnish的状态引擎;首先咱们来回顾下iptables报文的走向,在iptables里报文的走向有三种,第一种是从别的主机发送过来的报文,首先它会到达网卡,而后进入prerouting链,而后通过路由决策后,若是是发往本机的,则就走input链,从而把报文送给本机上的应用程序;第二种是从prerouting链经过路由决策后,不是发往本机的报文而是发往其余主机,经过本机转发的,它会从prerouting链到forward链,而后从postrouting链把报文发送给其余主机;第三种是从本机发往其余主机的报文,它的报文走向是从output链到postrouting链,而后从网卡发送出去;咱们说iptables的缘由是类比varnish的状态引擎;varnish的状态引擎就相似iptables里的这5链;咱们写的vcl配置就至关于iptables里的规则;他俩有个共同点就是在每一个链上的规则只对当前链上的表或者被自定义链引用才会生效,而varnish里的状态引擎也是一样的逻辑,咱们写的vcl配置只对当前状态引擎生效,不一样的状态引擎处有着不一样的意义,对其余状态引擎互不干扰;这样描述相信你们对varnish的状态引擎有了初步的概念,这也是咱们在上一篇文中说到的,发送给客户端的响应报文,为何要配置在vcl_deliver里,而不是其余位置;接下来咱们看看varnish的状态引擎;css
提示:以上这张图上varnish4.0的状态引擎图,每一个状态引擎彼此的关系,以及varnish内部缓存处理逻辑;首先当varnish服务器收到来自客户端的请求报文,最早到达的状态引擎是vcl_recv,咱们能够在vcl_recv里面对客户端的请求报文作修改,或者其余操做,而后交给vcl_hash这个状态引擎,这个状态引擎主要是看是否可查缓存,若是能够查缓存,会判断是否命中,命中就交给vcl_hit处理,vcl_hit处理后,就直接交给vcl_deliver处理,最后响应给客户端,固然缓存命中后也能够将请求交给vcl_pass处理;若是vcl_hash处理后不能查缓存,就把报文发送给vcl_miss处理,意思是不能查缓存,或者缓存未能命中;固然咱们也能够直接把报文交给vcl_pass处理;即使它能够被缓存命中,咱们也是能够强行让该请求不查缓存,直接交给vcl_pass处理或者vcl_miss直接交给vcl_backend_fatch处理;vcl_backend_fetch就是去后端真正的服务器上取对应资源,而后它会对后端服务器的响应报文头部进行读的操做,若是没有什么错误,就把响应报文发送给vcl_backend_response,vcl_backend_response在处理响应报文时,会判断是否可缓存,若是能够缓存,就在本地缓存一份,而后经过vcl_deliver响应给客户端,若是不可缓存,在本地就不缓存,直接将响应报文发送给vcl_deliver响应给客户端;若是vcl_backend_fetch读后端服务器发来的响应报文是错误响应(或者vcl_backend_fatch未取到对应资源,或者后端主机宕机等等),它就会把该处理逻辑交给vcl_backend_error处理;若是用户的请求通过vcl_hash处理后,发现缓存内容变了或者说缓存过时了须要修剪缓存,它会把请求发往vcl_purge,vcl_purge主要处理缓存修剪相关的操做,而后把请求报文发送给vcl_synth处理,合成一响应发送给客户端;若是经过vcl_hash处理后发现用户请求的方法咱们压根就不认识,这个时候会将请求报文交给vcl_pipe处理;html
从上面的图来看,咱们大概能够总结为两点,varnish的状态引擎分前端工做线程或者客户端状态引擎和后端工做线程或者服务端状态引擎;客户端状态引擎,主要处理客户端请求和响应相关的处理,好比是否可查缓存,是否命中,是否修剪缓存,是否识别用户请求的方法有或者直接交给vcl_pass,又或者说怎样响应客户端等等,能够看到客户端状态引擎vcl_pass,是一个额外处理机制,不论是否可查缓存,是否命中,均可以交给它处理;对于服务端状态引擎主要是处理和后端服务器请求和响应相关操做,好比怎样去后端服务器取资源,对服务器的响应报文是否可缓存,怎么缓存,对后端服务器的响应报文错误怎么处理等;前端
varnish的前端状态引擎有vcl_recv,vcl_pass, vcl_hit, vcl_miss, vcl_pipe, vcl_purge, vcl_synth, vcl_deliver;vcl_recv处理后能够经过return来指定下一跳处理的状态引擎是那个,若是是return(hash)就表示交给vcl_hash处理;return(pass)就表示交给vcl_pass处理;return(pipe)就表示交给vcl_pipe处理;return(synth)就表示交给vcl_synth处理;return(purge)就表示交给vcl_purge处理;对于vcl_hash来讲,return(hit)就表示缓存命中交给vcl_hit处理,return(miss)表示缓存未能命中交给vcl_miss处理,return(pass)或者return(hit_for_pass)就表示即使缓存命中也交给vcl_pass处理,return(purge)就表示交给vcl_purge处理;web
varnish的后端状态引擎有vcl_backend_fetch, vcl_backend_response, vcl_backend_error;vcl_backend_fetch处理去后端取资源的操做,vcl_backend_response处理后端服务器响应回来的报文,vcl_backend_error处理后端服务器错误;除此之外varinsh4.0还有两个特殊的状态引擎,分别是vcl_init和vcl_fini;vcl_init:在处理任何请求以前要执行的vcl代码:主要用于初始化VMODs;vcl_fini:全部的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;后端
了解了上面的状态引擎,咱们在说一说varnish的变量,在前文咱们大概说了下varnish的变量大概能够分5类,一类是客户端请求报文相关的,req.*;一类是varnish服务器请求后端服务器报文,bereq.*;一类是后端服务器响应varnish服务器的beresp.*;一类是varnish服务器响应客户端的resp.*;还有一类是obj.*,这类变量主要是储存缓存空间中的缓存对象的属性;结合上面说的状态引擎,不难里接在不一样的状态引擎里,对应变量是有限的,好比bereq.*这类变量就不能用于vcl_recv,由于vcl_recv是接收用户请求相关的,而bereq.* 是varnish请求后端服务器的变量,这二者很明显是再也不一个级别的,因此一般不一样类的变量对应可以用于哪些状态引擎中是有限制的;而对应变量的属性也是有要求的,好比obj.hit这个变量是存储缓存项命中次数的,一般可用在vcl_hit和vcl_deliver状态引擎中,表示应用缓存命中次数,相对于这个变量来讲,咱们是不能修改的,因此obj.hits这个变量在vcl_hit和vcl_deliver状态引擎中只可读,不可修改;而对于obj.ttl这个值就不同了;obj.ttl记录缓存项可缓存的时间;很显然obj.ttl这个变量只能用于可缓存的状态引擎上,好比vcl_hit,对于告诉客户端可缓存的时间,很明显它不能是一个不可修改的值;因此对于obj.ttl这个变量在vcl_hit状态引擎中就具备可读可写权限(即咱们能够修改该变量的值);说这么多无外乎就是表达一个意思,不一样类型的变量受限状态引擎,不一样变量在不一样的状态引擎上不是均可读可写,有的变量只可读;以下图浏览器
说明:以上这张表就是对于不一样类型的变量对应varnish的状态引擎是否可读写的,没有读写就表示该类型变量不能用于对应状态引擎中;好比resp.*只能在error和deliver状态引擎中使用;beresp.*这类变量只能用于后端主机响应varnish服务器的过程当中使用,好比fetch这个状态引擎就是处理后端服务器响应varnish服务器请求的;因此beresp.*这类变量只能用于fetch;固然这里的fetch是早期状态引擎的名称。在varnish4.0它不叫fetch,而叫vcl_backend_fatch;缓存
了解了以上内容,咱们接下来看几个示例服务器
示例:强制对某类资源的请求不检查缓存cookie
提示:以上配置表示对客户端请求的url进行判断,若是可以被.jpg、.jpeg、.png、.gif、.js、.css、.html匹配到,那么就把用户请求交给pass状态引擎处理;pass状态引擎处理就是不查缓存;因此对于客户端请求.jpg的资源,其对应obj.hits的值会一直为0;由于咱们明确指定了不查缓存;工具
测试:用浏览器访问服务器上的.jpg资源,看看响应报文中咱们自定义的X-Cache 首部是不是 miss via 192.168.0.99;
提示:能够看到咱们访问/day.jpg这个资源时,无论怎么刷新浏览器,对应响应首部X-Cache的值都是 miss via 192.168.0.99,说明咱们请求.jpg的资源的确没有查缓存;
示例:把客户端IP传到后端服务器
提示:以上vcl表示判断客户端请求首部X-Forwarded-For是否为空,若是不为空就把它的值在原有的值的基础上和客户端ip地址作字符串链接,并用逗号隔开;若是该首部为空或者没有这个首部就把这个首部的值设置成客户端ip地址;
更改后端web 服务的日志格式
提示:以上配置表示在日志格式中应用X-Forwarded-For这个首部的值;
测试:从新编译加载vcl,而后用浏览器访问,看看是否可以把浏览器所在主机的ip地址传到后端httpd服务器日志中作记录?
提示:从上面的日志结果看,咱们分别用不一样的浏览器去访问,在日志中能够看到不一样浏览器所在主机的IP地址,说明咱们经过判断用户请求报文X-Forwarded-For首部是否为空,从而实现对于非空和空值对应设置该首部值,继而实现把对应请求首部值记录到后端服务器日志中的目的;
示例:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其能够由varnish缓存的时长;
提示:首先咱们要清楚在那个位置去对报文操做,取消私有标识,是须要在后端服务器响应varnish这个过程当中把对应响应首部的值给撤销了;因此咱们须要在vcl_backend_response这个状态引擎中来设置,取消set-cookie首部,这个首部主要是给对应客户端设置一个cookie;以上配置表示判断后端服务器响应varnish服务器的响应报文首部cache-control的值是否匹配“s-maxage”,若是不匹配说明该资源不容许被共有缓存系统所缓存,若是匹配,则说明该资源容许被公有缓存系统所缓存;若是不匹配再继续判断varnish向后端请求的首部url的值是否匹配.jpg|jpeg|png|gif|css|js结尾的资源,若是匹配则取消后端服务器响应varnish服务器的响应首部set-cookie的值,并设置后端服务器响应varnish的资源缓存时长为1小时;简单讲就是判断后端服务器响应首部的cache-control的值是否匹配到“s-maxage”,若是不能匹配到在判断向后端服务器请求的首部url是不是匹配指定结尾的资源,若是是,就取消后端服务器响应首部set-cookie这个首部,同时把后端服务器响应资源的缓存时长设定为1小时;
测试:为了验证以上vcl配置正确性,咱们把beresp.ttl的值经过cache-control这个首部传递到浏览器响应首部,从而来判断set-cookie首部是被撤销了;
提示:在上面的配置中加入了set beresp.http.cache-control = beresp.ttl;表示把后端响应给varnish的响应首部beresp.ttl的值 经过beresp.http.cache-control首部保存;这样客户端访问.jpg的资源就会在响应首部中把cache-control的值给显示出来,若是该值是咱们设置的3600s,就说明咱们撤销set-cookie这个首部的vcl语句是生效的;
提示:从上面的结果看,cache-control的值为3600是咱们设置beresp.ttl的值;说明撤销set-cookie的vcl配置生效了;同时这也告诉咱们若是后端服务器响应varnish的报文中没有的首部,在varnish响应客户端中就没有;简单说就是varnish会把后端服务器响应给varnish中首部的值经过响应客户端首部传递出来;好比我在后端响应报文中自定义一个aaa的报文首部,其值为bbb,那么在客户端的响应报文首部中就会有对应aaa首部和对应的值;以下
测试:
提示:作以上测试须要考虑varnish上的缓存,若是你始终访问同一个url可能会看到对应首部的值不会发生变化,须要重启varnish或者换个其余符合vcl定义的url去访问试试看;