Varnish基础原理及简单配置

 <html>
<body>
<h1 style="text-align:center;color:red">Varnish基础原理及简单配置</h1>
<ol style="font-size:20px;font-weight:bold">
<style type="text/css">  
p{ text-indent:2em;}  
</style>
<li>Varnish简介:<br />
<p >
Varnish是一填款高性能的开源HTTP加速器,同时作为http反向缓存
补充资料:
    <a href="http://book.varnish-software.com/4.0/">http://book.varnish-software.com/4.0/</a>
</p >
特点
<ul>
<p>
<li>Varnis可以使用内存也可以使用硬盘进行数据缓存
<li>支持虚拟内存的使用
<li>有精确的时间管理机制
<li>状态引擎架构:通过特定的配置语言设计不同的语句
<li>以二叉堆格式管理数据
</p>
</ul>

优势:
<ul>
<p>
<li>varnish访问速度快,因为采用了“Visual Page Cache”技术,在读取数据时直接从内存中读取
<li>varnish支持更多的并发连接,因为varnish的TCP连接比squid快
<li>varnish通过管理端口,使用正则表达式批量的清除部分缓存
</p>
</ul>

劣势
<ul>
<p>
<li>进程一旦crash或重启,缓存的数据将从内存中完全释放,导致后端服务器压力过大,重新启动的热身时间,需要耗时数小时不等
<li>在多台varnish实现负载均衡时,每次请求都会落到不同的varnish服务器中,造成url请求可能会穿透到后端<br /><br />
解决方案:<br />
<p>
    A:在varnish的后端添加squid/nginx代理,这样防止了当varnish缓存被清空时,瞬间大量的请求发往web服务器<br /></p>
<p>    B:在负载均衡上做hash request_url,让单个url请求固定请求到一台varnish服务器上
</p>
</p>

</ul><br />


<li>varnish组成:
<p>
Management进程,用来管理进程,对child进程进行管理,同时对vcl配置进行编译<br /></p>
<p>child进程,子进程,生成线程池,负责处理用户请求</p>


阶段:
<p>
<ul>
<li>req:处理客户端发送的请求时使用
<li>bereq:处理varnish向后端服务器发送的请求时使用
<li>beresp:处理后端服务器响应时使用,用于varnish未缓存前
<li>resp:处理返回给客户端的响应时使用
<li>obj:处理存储在内存中的对象时使用
</ul>
</p><br /><br />

varnish工作流程图:


<li>客户端发送的请求对象
<table border="40" width="600" cellpadding="20" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">阶段对象</td><td>说明</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req</td><td>整个HTTP请求数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">req.backend_hint</td><td>指定请求的后端节点</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.http</td><td>对应请求HTTP的header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.can_gzip</td><td>客户端是否接受GZIP传输编码</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.hash_always_miss</td><td>是否强制不命中高速缓存</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.hash_ignore_busy</td><td>忽略缓存中忙碌的对象,多台缓存时可以避免死锁</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.method</td><td>请求类型(如GET,POST)</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.restarts</td><td>重新启动次数,默认最大值是4</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.ttl</td><td>缓存剩余时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.url</td><td>请求的url</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.xid</td><td>唯一ID</td></tr>
</table>




<li>发送到后端的请求对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq</td><td>整个后端请求后数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.backend</td><td>所请求后端节点配置</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.between_bytes_timeout</td><td>从后端每接收一个字节之间的等待时间(秒)</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.connect_timeout</td><td>连接后端等待时间(秒),最大等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.first_byte_timeout</td><td>等待后端第一个字节时间(秒),最大等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.http</td><td>对应发送到后端HTTP的header信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.method</td><td>发送到后端的请求类型</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.uncacheable</td><td>无缓存这个请求</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.url</td><td>发送到后端请求的URL</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.xid</td><td>请求唯一ID</td></tr>

</table>



<li>后端响应请求对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp</td><td>整个后端响应HTTP数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.backend.ip</td><td>后端响应的IP</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.backend.name</td><td>响应后端配置节点的name</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.do_gunzip</td><td>默认为false,缓存前解压该对象</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.do_gzip</td><td>默认为false,缓存前压缩该对象</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.grace</td><td>设置当前对象缓存过期后可额外宽限时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.http</td><td>对应的HTTP请求header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.keep</td><td>对象缓存后带保持时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.reason</td><td>由服务器返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.status</td><td>由服务器返回的状态码</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.storage_hint</td><td>指定保存的特定存储器</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.ttl</td><td>该对象缓存的剩余时间,指定统一缓存剩余时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.uncacheable</td><td>继承bereq.uncacheable,是否不缓存</td></tr>

</table>




<li>高速缓存对象,缓存后端响应请求内容
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.grace</td><td>该对象额外宽限时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.hits</td><td>缓存命中次数</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.http</td><td>对应HTTP的header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">obj.reason</td><td>服务器返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.status</td><td></td>服务器返回的状态码</tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.ttl</td><td>该对象缓存剩余时间秒</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.uncacheable</td><td>不缓存对象</td></tr>

</table>




<li>返回给客户端的响应对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp</td><td>整个响应HTTP数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.http</td><td>对应HTTP的hearder</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.proto</td><td>编辑响应的HTTP协议版本</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.reason</td><td>将要返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.status</td><td>将要返回的HTTP状态码</td></tr>

</table>
<br /><br />



<li>运算符:<br />
<ul type="square">
    <li>=:赋值运算<br />
    <li>==:相等比较<br />
    <li>~ :匹配,可以使用正则表达式,或访问控制列表<br />
    <li>!~:不匹配,可以使用正则表达式,或访问控制列表<br />
    <li>! :非<br />
    <li>&&:逻辑与<br />
    <li>||:逻辑或<br />
</ul>
<br /><br />
<li>功能语句与对象<br />
    一般功能语句都用于匹配对象,就是对某个对象实现什么操作
<ul type="square">
    <li>ban():清除指定对象缓存<br />
    <li>ban_url(regex):可以清除被此处匹配到的缓存<br />
    <li>call():调用子程序<br />
    <li>hash_data():生成hash键值,只能在vck_hash子程序中使用<br />
    <li>new():创建一个vcl对象,只能在vcl_init子程序中使用<br />
    <li>return():结束当前子程序并执行下一步动作<br />
    <li>rollback():恢复http头到原来的状态,现在使用std.rollback()代替<br />
    <li>synthetic():合成器,用于自定义一个响应内容,只能在vcl_synth和vcl_backend_error子程序中使用<br />
    <li>regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite<br />
    <li>regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;<br />



</ul>


<li>
<ul>return的常用动作<br />
    语法:return (action)<br />
        <li type="square">abandon:放弃处理,并生成一个错误
        <li type="square">deliver:交付至后端处理
        <li type="square">fetch:从后端取出响应对象
        <li type="square">hash:哈希缓存处理
        <li type="square">lookup:从缓存中查找应答数据并返回,如果查找不到,则调用pass函数,从后端服务器调用数据
        <li type="square">ok:继续执行

        <li type="square">pass:绕过缓存,直接向后端服务器调用数据
        <li type="square">pipe: 建立客户端和后端服务器之间的直接连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到断开连接
        <li type="square">purge:清除缓存对象,构建响应
        <li type="square">restart:重新开始
        <li type="square">retry: 重试后端处理
        <li type="square">synth  合成响应报文,响应客户端    
</ul>
<br />
<ul style="color:green">varnish中内置子程序:<br />
    
        <li type="square">子进程也叫状态引擎,每一个状态引擎均有自己限定的返回动作return,不同的动作将调用对应下一个状态引擎。</li><br />
        <li type="square">我们可以把一个请求分为多个阶段,每个阶段都会调用不同的状态引擎去操作,这样,我们只编写出相应的状态引擎,就可认控制每个请求阶段</li><br />
        <li type="square">varnish内置子程序均有自己限定的返回动作return,不同的动作将调用对应下一个子程序
        每个子程序都需要通过关键字sub进行定义</li><br />

</ul>








<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_recv子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">开始处理请求,通过return(动作);选择varnish处理模式,默认进入hash缓存模式(即return(hash);),缓存时间为配置default_ttl(默认为120秒)过期保持时间default_grace(过期容忍时间,默认为10秒)。该子程序一般用于模式选择,对象缓存及信息修改,后端节点修改,终止请求等操作</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">返回值:synth,pass,pipe,hash,pruge</td></tr>
</td></tr>
</table>





<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">vcl_pipe子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">pipe模式处理,该模式主要用于直接取后端响应内容返回客户端,可定义响应内容返回客户端。该子程序一般用于需要及时且不作处理的后端信息,取出后端响应内容后直接交付到客户端不进入vcl_deliver子程序处理</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">返回值:synth,pipe</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_pass子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">pass模式处理,该模式类似hash缓存模式,仅不做缓存处理</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:synth,fetch:继续pass模式,进入后端vcl_backend_fetch子程序,默认返回值</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_hit子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式时存在hash缓存时调用,用于缓存处理,可放弃或修改缓存</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:restart,deliver默认返回值,synth</td></tr>
</table>


<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_miss子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式时不存在hash缓存时调用,用于判断性的选择进入后端取响应内容,可以修改为pass模式</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:restart重启请求,synth,pass,fetch:正常取后端内容再缓存,进入vcl_backend_fetch子程序,默认返回值</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_hash</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式,生成hash值作为缓存查找键名提取缓存内容,主要用于缓存hash键值处理,可使用hash_data(string)指定键值组成结构,可在同一页面通过IP或Cookie生成不同的缓存键值</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:lookup:查找缓存对象,存在缓存进入vcl_hit子程序,不存在缓存进入vcl_miss子程序,当使用了purge清理模式时会进入vcl_purge子程序,默认返回值</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">acl_purge子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">清理模式,当查找到对应的缓存时清除并调用,用于请求方法清除缓存,并报告</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:synth,restart</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_deliver子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">客户端交付子程序,在vcl_backend_response子程序后调用(非pipe模式),或vcl_hit子程序后调用,可用于追加响应头信息,cookie等内容</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,restart</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_fetch子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">发送后端请求之前调用,可用于改变请求地址或其它信息,或放弃请求</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:fetch:正常发送请求到后端取出响应内容,进入vcl_backend_response子程序,默认返回值,abandon</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_redponse子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">后端响应后调用,可用于修改缓存时间及缓存相关信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,abandon,retry:重试后端请求,重试计数器加1,当超过配置中max_retries值时会报错并进入vcl_backend_error子程序</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_error子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">后端处理失败调用,异常页面展示效果处理,可自定义错误响应内容,或修改beresp.status与beresp.http.Location重定向等</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,retry</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_synth子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">自定义响应内容,可以通过synthetic()和返回值synth调用,这里可以自定义异常显示内容,也可以修改resp.status与resp.http.Location重定向</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,restart</td></tr>
</table>





<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_init子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">加载vcl时最先调用,用于初始化VMODs,该子程序不参与请求处理,仅在vcl加载时调用一次</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:ok</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_fini子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">卸载当前vcl配置时调用,用于清理VMODs,该子程序不参与请求处理,仅在vcl正常丢弃后调用</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:ok</td></tr>
</table>
<br /><br />








<li><p style="font-size:25px;font-weight:bold;color:green">后端服务器定义:</p>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">属性</td><td>说明</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.host= "IP";</td><td>要转向主机(即后端主机)的IP或域名,必填键值对</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.port = "80";</td><td>主机连接端口号或协议名(HTTP等),默认80</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.connect_timeout = 0.5s;</td><td>连接后端主机的超时时长</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.first_byte_timeout = 2s;</td><td>等待从后端返回的第一个字节时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.between_bytes_timeout = 2s;</td><td>每接收一个字节之间等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.probe = probe_name</td><td>监控后端主机的状态,指定外部监控name或者内部直接添加</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.max_connections = 1000;</td><td>设置最大并发连接数,超过这个数后连接就会失败</td></tr>

</table>
















<li><p style="font-size:25px;font-weight:bold;color:green">监视器定义</p>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.url = "/";</td><td>指定监控入口地址,默认为“/”</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.request = "";</td><td>指定监控请求入口地址,比.url优先级高</td></tr>


<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.timeout = "";</td><td>超时时长</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.window = "";</td><td>基于最近的多少次检查来判断其健康状态,默认为8</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.threshold = "";</td><td>最近.window中定义的这么次检查中至少有.threshold定义的次数是成功的,默认是3</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.interval = "";</td><td>检测频度,默认为5秒</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.initial = -1</td><td>window中有几次是良好启用此节点</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.expected_reponse = "";</td><td>期望的响应码,默认为200</td></tr>
</table><br />

<li>检测实例:
<pre>
probe check {
        .url = "/";
        .timeout = 2s;
        .interval = 2s;    <code style="color:red;font-size:20px">//这里又引入了新的问题,虽然会去自动检测后端主机的健康性,但是后端主机会记录日志的,如果设定的时间过短,会增大后端服务器的磁盘压力,过长,则会使用户感觉不好,设一个稳点的值</code>
        .window = 8;
        .threshold = 6;
}

backend websrv {
        .host = "172.16.252.113";
        .port = "80";
        .max_connections = 500;
        .probe = check;
}


<code style="color:green">>backend.list</code>
200        
Backend name                   Refs   Admin      Probe
websrv(172.16.252.113,,80)     4      probe      Sick 5/8   //检测出来的效果sick生病了
default(127.0.0.1,,8080)       4      probe      Healthy (no probe)
backend.list
200        
Backend name                   Refs   Admin      Probe
websrv(172.16.252.113,,80)     4      probe      Sick 4/8
default(127.0.0.1,,8080)       4      probe      Healthy (no probe)
backend.list
200        
</pre><br /><br />



<li><p style="font-size;20px;font-weight:bold;color:blue">PURGE和BAN操作,来清理特定的缓存,也可以在命令行中执行</p>
<pre>
acl purgers {
    "127.0.0.1";
    "192.168.0.0"/24;
}

sub vcl_recv {
    # allow PURGE from localhost and 192.168.0...
    if (req.method == "PURGE") {
        if (!client.ip ~ purgers) {
            return (synth(405, "Purging not allowed for " + client.ip));
        }
        return (purge);
    }
}

sub vcl_purge {
    return (synth(200,"Purged,now!"));
#   set req.method = "GET";
#   return (restart);
}
    if (req.method == "BAN") {
        if (!client.ip ~ purgers) {
        return (synth(405,"Banning not allowd for" + client.ip));
        }
<code style="color:red">   ban(" req.http.host == " + req.http.host + " && req.url == " + req.url); </code>  //运算符边上必须有空格,要不然会实现不了功能的
    return (synth(200,"Ban added."));
    }



操作:
<code style="color:green">~]# varnish -S /etc/varnish/secret -T 127.0.0.1:6082</code>
vcl.load test1 default.vcl
vcl.use test1 
也可在此操作清除缓存:
ban req.url ~ .js$    //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便


客户端操作:
<code style="color:green">~]# crul -I http://172.16.254.35</code>
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 27 Jun 2017 09:27:38 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 27 Jun 2017 06:21:47 GMT
ETag: "5951f97b-11"
X-Varnish: 3964978
Age: 0
Via: 1.1 varnish-v4
X-Cache: Miss via172.16.254.35  //没有命中
Connection: keep-alive

<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...

进行PURGE操作:
<code style="color:green">~]# curl -X PURGE http://172.16.254.35/index.html</code>
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
...
X-Cache: Miss via172.16.254.35  //不能命中缓存
...
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...

进行BAN操作:
<code style="color:green">~]# curl -X BAN http://172.16.254.35/index.html</code>
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
...
X-Cache: Miss via172.16.254.35  //不能命中缓存
...
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...    
</pre>
<br /><br />




<li>实例:在缓存中,强制对某类资源的请求不检查缓存:
<pre>
vcl_recv {
    if (req.url ~ "(?i)^/(login|admin)") {   //(?i)不区分字符大小写
        return(pass);
    }
}    
</pre>
<br />

<li>实例:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长;定义在vcl_backend_response中
<pre>
if (beresp.http.cache-control !~ "s-maxage") {    //如果后端服务器没有给缓存时长
    if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {   //同时匹配以.jpg...结尾的文件
        unset beresp.http.Set-Cookie;  <code style="color:red">//说明:默认情况下,varnish不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,varnish将忽略缓存,直接将请求递送至后端服务器上</code>
        set beresp.ttl = 3600s;  //设置后端响应首部的生存时长为1h
    }
}
</pre><br />

<li>实例:将真实的客户IP地址转移至后端服务器上,以便日志记录
<pre>
if (req.restarts == 0) {
    if (req.http.X-Fowarded-For) {
        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
    } else {
        set req.http.X-Forwarded-For = client.ip;
    }
}
</pre><br /><br />


<li>最后的一个整体笔记:
<pre style="background:black;color:white;font-size:20px">
import directors;   <code style="color:red;font-size:20px">//负载均衡集群需要directors模块支持,import directors</code>

acl purgers {    <code style="color:red;font-size:20px">//对缓存资源进行控制</code>
        "127.0.0.1";
        "172.16.0.0"/16;
}



probe check {    <code style="color:red;font-size:20px">//对后端服务器的状态检测</code>
        .url = "/";
        .timeout = 2s;
        .interval = 10s;
        .window = 8;
        .threshold = 6;
}

backend websrv {      <code style="color:red;font-size:20px">//定义后端主机的属性</code>
        .host = "172.16.252.113";
        .port = "80";
        .max_connections = 500;
        .port = "80";
        .max_connections = 500;
        .probe = check;      <code style="color:red;font-size:20px">//执行健康状态检测</code>
}
backend websrv2 {
        .host = "172.16.250.84";
        .port = "80";
        .probe = check;
}




# Default backend definition. Set this to point to your content server.
backend default {      
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_init {      <code style="color:red;font-size:20px">//初始化子程序创建后端主机组,即directors</code>
        new WEBGROUP = directors.round_robin();   <code style="color:red;font-size:20px">//使用new关键字创建director对象,使用round_robin算法</code>
        WEBGROUP.add_backend(websrv);
        WEBGROUP.add_backend(websrv2);
        WEBGROUP.add_backend(websrv);
        WEBGROUP.add_backend(websrv2);
}


sub vcl_recv {           <code style="color:red;font-size:20px">//接受请求子程序</code>

        set req.backend_hint = WEBGROUP.backend(); <code style="color:red;font-size:20px">//调用后端主机组</code>

        if (req.url ~ "(?i)\.(JPG|PNG|GIF)") {   <code style="color:red;font-size:20px">//对几种图片不进行缓存查找</code>
                return(pass);
        }

        if (req.restarts == 0) {     <code style="color:red;font-size:20px">//IP地址转移</code>
                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.method == "PURGE") {   <code style="color:red;font-size:20px">//对某个缓存对象进行清理操作</code>
                if (!client.ip ~ purgers) {
                        return (synth(405,"Purging not allowed for" + client.ip));
                }
        return (purge);    <code style="color:red;font-size:20px">//去往purge子程序操作</code>
        }

        if (req.method == "BAN") {     <code style="color:red;font-size:20px">//清理某一类缓存对象</code>
                if (!client.ip ~ purgers) {
                        return (synth(405,"Banning not allowd for" + client.ip));
                }
                ban("req.http.host == " + req.http.host + " && req.url == " + req.url);<code style="color:red;font-size:20px">//清除host+url的对象</code>
                return (synth(200,"Ban added."));    
        }

#       if (req.url ~ "(?i)\.php$") {      <code style="color:red;font-size:20px">//以.php请求至后端</code>
#               set req.backend_hint = websrv;
#       } else {
#               set req.backend_hint = default;
#       }
}


sub vcl_purge {    <code style="color:red;font-size:20px">//purge子程序</code>
        return (synth(200,"Purged"));<code style="color:red;font-size:20px">//合成信息,并返回值</code>
#       set req.method = "GET";<code style="color:red;font-size:20px">//将请求方法设置成GET</code>
#       return (restart);<code style="color:red;font-size:20px">//在发还给客户端,让客户端重新来取</code>

}



sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}


sub vcl_deliver {   <code style="color:red;font-size:20px">//发送给客户的数据报文</code>
    if (obj.hits>0) {   <code style="color:red;font-size:20px">//测试用,如果 有缓存,就把X-Cache首部信息发给客户端</code>
        set resp.http.X-Cache = "Hit via" + server.ip;
    } else {
        set resp.http.X-Cache = "Miss via" + server.ip;
    }
}
</pre>
<br /><br />


<p style="font-size:25px;color:green">varnish日志区域:
<br />
<style type="text/css">  
p{ text-indent:2em;}  
</style>
1、varnishstat - Varnish Cache statistics<br />
                
<p>            -1  //显示一次<br /></p>
<p>                -1 -f FILED_NAME </p>
<p>                -l:可用于-f选项指定的字段名称列表;</p>
                
<p>                MAIN.cache_hit </p>
<p>                MAIN.cache_miss</p>
                
<p>                # varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss</p>
<p>                # varnishstat -l -f MAIN -f MEMPOOL</p>
                
<p>            2、varnishtop - Varnish log entry ranking</p>
<p>                -1     Instead of a continously updated display, print the statistics once and exit.</p>
<p>                -i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;</p>
<p>                -I <[taglist:]regex></p>
<p>                -x taglist:排除列表</p>
<p>                -X  <[taglist:]regex></p>
                
<p>            3、varnishlog - Display Varnish logs</p>
                
<p>            4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format</p>

</p>

<code style="font-size:20px;color:green">systemctl start varnishncsa.service   //开启日志功能服务</code>









</ol>
</body>
</html> <html>
<body>
<h1 style="text-align:center;color:red">Varnish基础原理及简单配置</h1>
<ol style="font-size:20px;font-weight:bold">
<style type="text/css">  
p{ text-indent:2em;}  
</style>
<li>Varnish简介:<br />
<p >
Varnish是一填款高性能的开源HTTP加速器,同时作为http反向缓存
补充资料:
    <a href="http://book.varnish-software.com/4.0/">http://book.varnish-software.com/4.0/</a>
</p >
特点
<ul>
<p>
<li>Varnis可以使用内存也可以使用硬盘进行数据缓存
<li>支持虚拟内存的使用
<li>有精确的时间管理机制
<li>状态引擎架构:通过特定的配置语言设计不同的语句
<li>以二叉堆格式管理数据
</p>
</ul>

优势:
<ul>
<p>
<li>varnish访问速度快,因为采用了“Visual Page Cache”技术,在读取数据时直接从内存中读取
<li>varnish支持更多的并发连接,因为varnish的TCP连接比squid快
<li>varnish通过管理端口,使用正则表达式批量的清除部分缓存
</p>
</ul>

劣势
<ul>
<p>
<li>进程一旦crash或重启,缓存的数据将从内存中完全释放,导致后端服务器压力过大,重新启动的热身时间,需要耗时数小时不等
<li>在多台varnish实现负载均衡时,每次请求都会落到不同的varnish服务器中,造成url请求可能会穿透到后端<br /><br />
解决方案:<br />
<p>
    A:在varnish的后端添加squid/nginx代理,这样防止了当varnish缓存被清空时,瞬间大量的请求发往web服务器<br /></p>
<p>    B:在负载均衡上做hash request_url,让单个url请求固定请求到一台varnish服务器上
</p>
</p>

</ul><br />


<li>varnish组成:
<p>
Management进程,用来管理进程,对child进程进行管理,同时对vcl配置进行编译<br /></p>
<p>child进程,子进程,生成线程池,负责处理用户请求</p>


阶段:
<p>
<ul>
<li>req:处理客户端发送的请求时使用
<li>bereq:处理varnish向后端服务器发送的请求时使用
<li>beresp:处理后端服务器响应时使用,用于varnish未缓存前
<li>resp:处理返回给客户端的响应时使用
<li>obj:处理存储在内存中的对象时使用
</ul>
</p><br /><br />

varnish工作流程图:


<li>客户端发送的请求对象
<table border="40" width="600" cellpadding="20" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">阶段对象</td><td>说明</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req</td><td>整个HTTP请求数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">req.backend_hint</td><td>指定请求的后端节点</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.http</td><td>对应请求HTTP的header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.can_gzip</td><td>客户端是否接受GZIP传输编码</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.hash_always_miss</td><td>是否强制不命中高速缓存</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.hash_ignore_busy</td><td>忽略缓存中忙碌的对象,多台缓存时可以避免死锁</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.method</td><td>请求类型(如GET,POST)</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.restarts</td><td>重新启动次数,默认最大值是4</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.ttl</td><td>缓存剩余时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.url</td><td>请求的url</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">req.xid</td><td>唯一ID</td></tr>
</table>




<li>发送到后端的请求对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq</td><td>整个后端请求后数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.backend</td><td>所请求后端节点配置</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.between_bytes_timeout</td><td>从后端每接收一个字节之间的等待时间(秒)</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.connect_timeout</td><td>连接后端等待时间(秒),最大等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.first_byte_timeout</td><td>等待后端第一个字节时间(秒),最大等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.http</td><td>对应发送到后端HTTP的header信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.method</td><td>发送到后端的请求类型</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.uncacheable</td><td>无缓存这个请求</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.url</td><td>发送到后端请求的URL</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">bereq.xid</td><td>请求唯一ID</td></tr>

</table>



<li>后端响应请求对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp</td><td>整个后端响应HTTP数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.backend.ip</td><td>后端响应的IP</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.backend.name</td><td>响应后端配置节点的name</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.do_gunzip</td><td>默认为false,缓存前解压该对象</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.do_gzip</td><td>默认为false,缓存前压缩该对象</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.grace</td><td>设置当前对象缓存过期后可额外宽限时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.http</td><td>对应的HTTP请求header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.keep</td><td>对象缓存后带保持时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.reason</td><td>由服务器返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.status</td><td>由服务器返回的状态码</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.storage_hint</td><td>指定保存的特定存储器</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.ttl</td><td>该对象缓存的剩余时间,指定统一缓存剩余时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">beresp.uncacheable</td><td>继承bereq.uncacheable,是否不缓存</td></tr>

</table>




<li>高速缓存对象,缓存后端响应请求内容
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.grace</td><td>该对象额外宽限时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.hits</td><td>缓存命中次数</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.http</td><td>对应HTTP的header</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">obj.reason</td><td>服务器返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.status</td><td></td>服务器返回的状态码</tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.ttl</td><td>该对象缓存剩余时间秒</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">obj.uncacheable</td><td>不缓存对象</td></tr>

</table>




<li>返回给客户端的响应对象
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp</td><td>整个响应HTTP数据结构</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.http</td><td>对应HTTP的hearder</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.proto</td><td>编辑响应的HTTP协议版本</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.reason</td><td>将要返回的HTTP状态信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"><td width="200">resp.status</td><td>将要返回的HTTP状态码</td></tr>

</table>
<br /><br />



<li>运算符:<br />
<ul type="square">
    <li>=:赋值运算<br />
    <li>==:相等比较<br />
    <li>~ :匹配,可以使用正则表达式,或访问控制列表<br />
    <li>!~:不匹配,可以使用正则表达式,或访问控制列表<br />
    <li>! :非<br />
    <li>&&:逻辑与<br />
    <li>||:逻辑或<br />
</ul>
<br /><br />
<li>功能语句与对象<br />
    一般功能语句都用于匹配对象,就是对某个对象实现什么操作
<ul type="square">
    <li>ban():清除指定对象缓存<br />
    <li>ban_url(regex):可以清除被此处匹配到的缓存<br />
    <li>call():调用子程序<br />
    <li>hash_data():生成hash键值,只能在vck_hash子程序中使用<br />
    <li>new():创建一个vcl对象,只能在vcl_init子程序中使用<br />
    <li>return():结束当前子程序并执行下一步动作<br />
    <li>rollback():恢复http头到原来的状态,现在使用std.rollback()代替<br />
    <li>synthetic():合成器,用于自定义一个响应内容,只能在vcl_synth和vcl_backend_error子程序中使用<br />
    <li>regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite<br />
    <li>regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;<br />



</ul>


<li>
<ul>return的常用动作<br />
    语法:return (action)<br />
        <li type="square">abandon:放弃处理,并生成一个错误
        <li type="square">deliver:交付至后端处理
        <li type="square">fetch:从后端取出响应对象
        <li type="square">hash:哈希缓存处理
        <li type="square">lookup:从缓存中查找应答数据并返回,如果查找不到,则调用pass函数,从后端服务器调用数据
        <li type="square">ok:继续执行

        <li type="square">pass:绕过缓存,直接向后端服务器调用数据
        <li type="square">pipe: 建立客户端和后端服务器之间的直接连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到断开连接
        <li type="square">purge:清除缓存对象,构建响应
        <li type="square">restart:重新开始
        <li type="square">retry: 重试后端处理
        <li type="square">synth  合成响应报文,响应客户端    
</ul>
<br />
<ul style="color:green">varnish中内置子程序:<br />
    
        <li type="square">子进程也叫状态引擎,每一个状态引擎均有自己限定的返回动作return,不同的动作将调用对应下一个状态引擎。</li><br />
        <li type="square">我们可以把一个请求分为多个阶段,每个阶段都会调用不同的状态引擎去操作,这样,我们只编写出相应的状态引擎,就可认控制每个请求阶段</li><br />
        <li type="square">varnish内置子程序均有自己限定的返回动作return,不同的动作将调用对应下一个子程序
        每个子程序都需要通过关键字sub进行定义</li><br />

</ul>








<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_recv子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">开始处理请求,通过return(动作);选择varnish处理模式,默认进入hash缓存模式(即return(hash);),缓存时间为配置default_ttl(默认为120秒)过期保持时间default_grace(过期容忍时间,默认为10秒)。该子程序一般用于模式选择,对象缓存及信息修改,后端节点修改,终止请求等操作</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">返回值:synth,pass,pipe,hash,pruge</td></tr>
</td></tr>
</table>





<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">vcl_pipe子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">pipe模式处理,该模式主要用于直接取后端响应内容返回客户端,可定义响应内容返回客户端。该子程序一般用于需要及时且不作处理的后端信息,取出后端响应内容后直接交付到客户端不进入vcl_deliver子程序处理</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:purple"> <td width="200">返回值:synth,pipe</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_pass子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">pass模式处理,该模式类似hash缓存模式,仅不做缓存处理</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:synth,fetch:继续pass模式,进入后端vcl_backend_fetch子程序,默认返回值</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_hit子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式时存在hash缓存时调用,用于缓存处理,可放弃或修改缓存</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:restart,deliver默认返回值,synth</td></tr>
</table>


<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_miss子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式时不存在hash缓存时调用,用于判断性的选择进入后端取响应内容,可以修改为pass模式</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:restart重启请求,synth,pass,fetch:正常取后端内容再缓存,进入vcl_backend_fetch子程序,默认返回值</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_hash</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">hash缓存模式,生成hash值作为缓存查找键名提取缓存内容,主要用于缓存hash键值处理,可使用hash_data(string)指定键值组成结构,可在同一页面通过IP或Cookie生成不同的缓存键值</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:lookup:查找缓存对象,存在缓存进入vcl_hit子程序,不存在缓存进入vcl_miss子程序,当使用了purge清理模式时会进入vcl_purge子程序,默认返回值</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">acl_purge子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">清理模式,当查找到对应的缓存时清除并调用,用于请求方法清除缓存,并报告</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:synth,restart</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_deliver子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">客户端交付子程序,在vcl_backend_response子程序后调用(非pipe模式),或vcl_hit子程序后调用,可用于追加响应头信息,cookie等内容</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,restart</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_fetch子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">发送后端请求之前调用,可用于改变请求地址或其它信息,或放弃请求</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:fetch:正常发送请求到后端取出响应内容,进入vcl_backend_response子程序,默认返回值,abandon</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_redponse子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">后端响应后调用,可用于修改缓存时间及缓存相关信息</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,abandon,retry:重试后端请求,重试计数器加1,当超过配置中max_retries值时会报错并进入vcl_backend_error子程序</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_backend_error子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">后端处理失败调用,异常页面展示效果处理,可自定义错误响应内容,或修改beresp.status与beresp.http.Location重定向等</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,retry</td></tr>
</table>




<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_synth子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">自定义响应内容,可以通过synthetic()和返回值synth调用,这里可以自定义异常显示内容,也可以修改resp.status与resp.http.Location重定向</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:deliver,restart</td></tr>
</table>





<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_init子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">加载vcl时最先调用,用于初始化VMODs,该子程序不参与请求处理,仅在vcl加载时调用一次</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:ok</td></tr>
</table>



<li>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold;color:blue"> <td width="200">vcl_fini子程序</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">卸载当前vcl配置时调用,用于清理VMODs,该子程序不参与请求处理,仅在vcl正常丢弃后调用</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold;color:grey"> <td width="200">返回值:ok</td></tr>
</table>
<br /><br />








<li><p style="font-size:25px;font-weight:bold;color:green">后端服务器定义:</p>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">属性</td><td>说明</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.host= "IP";</td><td>要转向主机(即后端主机)的IP或域名,必填键值对</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.port = "80";</td><td>主机连接端口号或协议名(HTTP等),默认80</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.connect_timeout = 0.5s;</td><td>连接后端主机的超时时长</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.first_byte_timeout = 2s;</td><td>等待从后端返回的第一个字节时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.between_bytes_timeout = 2s;</td><td>每接收一个字节之间等待时间</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.probe = probe_name</td><td>监控后端主机的状态,指定外部监控name或者内部直接添加</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.max_connections = 1000;</td><td>设置最大并发连接数,超过这个数后连接就会失败</td></tr>

</table>
















<li><p style="font-size:25px;font-weight:bold;color:green">监视器定义</p>
<table border="20" width="600" cellpadding="0" cellspacing="0"> 

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.url = "/";</td><td>指定监控入口地址,默认为“/”</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.request = "";</td><td>指定监控请求入口地址,比.url优先级高</td></tr>


<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.timeout = "";</td><td>超时时长</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.window = "";</td><td>基于最近的多少次检查来判断其健康状态,默认为8</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.threshold = "";</td><td>最近.window中定义的这么次检查中至少有.threshold定义的次数是成功的,默认是3</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.interval = "";</td><td>检测频度,默认为5秒</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.initial = -1</td><td>window中有几次是良好启用此节点</td></tr>

<tr style="text-align:center;font-size:20px;font-weight:bold"> <td width="200">.expected_reponse = "";</td><td>期望的响应码,默认为200</td></tr>
</table><br />

<li>检测实例:
<pre>
probe check {
        .url = "/";
        .timeout = 2s;
        .interval = 2s;    <code style="color:red;font-size:20px">//这里又引入了新的问题,虽然会去自动检测后端主机的健康性,但是后端主机会记录日志的,如果设定的时间过短,会增大后端服务器的磁盘压力,过长,则会使用户感觉不好,设一个稳点的值</code>
        .window = 8;
        .threshold = 6;
}

backend websrv {
        .host = "172.16.252.113";
        .port = "80";
        .max_connections = 500;
        .probe = check;
}


<code style="color:green">>backend.list</code>
200        
Backend name                   Refs   Admin      Probe
websrv(172.16.252.113,,80)     4      probe      Sick 5/8   //检测出来的效果sick生病了
default(127.0.0.1,,8080)       4      probe      Healthy (no probe)
backend.list
200        
Backend name                   Refs   Admin      Probe
websrv(172.16.252.113,,80)     4      probe      Sick 4/8
default(127.0.0.1,,8080)       4      probe      Healthy (no probe)
backend.list
200        
</pre><br /><br />



<li><p style="font-size;20px;font-weight:bold;color:blue">PURGE和BAN操作,来清理特定的缓存,也可以在命令行中执行</p>
<pre>
acl purgers {
    "127.0.0.1";
    "192.168.0.0"/24;
}

sub vcl_recv {
    # allow PURGE from localhost and 192.168.0...
    if (req.method == "PURGE") {
        if (!client.ip ~ purgers) {
            return (synth(405, "Purging not allowed for " + client.ip));
        }
        return (purge);
    }
}

sub vcl_purge {
    return (synth(200,"Purged,now!"));
#   set req.method = "GET";
#   return (restart);
}
    if (req.method == "BAN") {
        if (!client.ip ~ purgers) {
        return (synth(405,"Banning not allowd for" + client.ip));
        }
<code style="color:red">   ban(" req.http.host == " + req.http.host + " && req.url == " + req.url); </code>  //运算符边上必须有空格,要不然会实现不了功能的
    return (synth(200,"Ban added."));
    }



操作:
<code style="color:green">~]# varnish -S /etc/varnish/secret -T 127.0.0.1:6082</code>
vcl.load test1 default.vcl
vcl.use test1 
也可在此操作清除缓存:
ban req.url ~ .js$    //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便


客户端操作:
<code style="color:green">~]# crul -I http://172.16.254.35</code>
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 27 Jun 2017 09:27:38 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 27 Jun 2017 06:21:47 GMT
ETag: "5951f97b-11"
X-Varnish: 3964978
Age: 0
Via: 1.1 varnish-v4
X-Cache: Miss via172.16.254.35  //没有命中
Connection: keep-alive

<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...

进行PURGE操作:
<code style="color:green">~]# curl -X PURGE http://172.16.254.35/index.html</code>
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
...
X-Cache: Miss via172.16.254.35  //不能命中缓存
...
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...

进行BAN操作:
<code style="color:green">~]# curl -X BAN http://172.16.254.35/index.html</code>
...
Error 405 Purging not allowed for172.16.251.81
...
再次访问:
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
...
X-Cache: Miss via172.16.254.35  //不能命中缓存
...
<code style="color:green">~]# curl -I http://172.16.254.35/index.html</code>
....
X-Cache: Hit via172.16.254.35  //命中
...    
</pre>
<br /><br />




<li>实例:在缓存中,强制对某类资源的请求不检查缓存:
<pre>
vcl_recv {
    if (req.url ~ "(?i)^/(login|admin)") {   //(?i)不区分字符大小写
        return(pass);
    }
}    
</pre>
<br />

<li>实例:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长;定义在vcl_backend_response中
<pre>
if (beresp.http.cache-control !~ "s-maxage") {    //如果后端服务器没有给缓存时长
    if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {   //同时匹配以.jpg...结尾的文件
        unset beresp.http.Set-Cookie;  <code style="color:red">//说明:默认情况下,varnish不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,varnish将忽略缓存,直接将请求递送至后端服务器上</code>
        set beresp.ttl = 3600s;  //设置后端响应首部的生存时长为1h
    }
}
</pre><br />

<li>实例:将真实的客户IP地址转移至后端服务器上,以便日志记录
<pre>
if (req.restarts == 0) {
    if (req.http.X-Fowarded-For) {
        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
    } else {
        set req.http.X-Forwarded-For = client.ip;
    }
}
</pre><br /><br />


<li>最后的一个整体笔记:
<pre style="background:black;color:white;font-size:20px">
import directors;   <code style="color:red;font-size:20px">//负载均衡集群需要directors模块支持,import directors</code>

acl purgers {    <code style="color:red;font-size:20px">//对缓存资源进行控制</code>
        "127.0.0.1";
        "172.16.0.0"/16;
}



probe check {    <code style="color:red;font-size:20px">//对后端服务器的状态检测</code>
        .url = "/";
        .timeout = 2s;
        .interval = 10s;
        .window = 8;
        .threshold = 6;
}

backend websrv {      <code style="color:red;font-size:20px">//定义后端主机的属性</code>
        .host = "172.16.252.113";
        .port = "80";
        .max_connections = 500;
        .port = "80";
        .max_connections = 500;
        .probe = check;      <code style="color:red;font-size:20px">//执行健康状态检测</code>
}
backend websrv2 {
        .host = "172.16.250.84";
        .port = "80";
        .probe = check;
}




# Default backend definition. Set this to point to your content server.
backend default {      
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_init {      <code style="color:red;font-size:20px">//初始化子程序创建后端主机组,即directors</code>
        new WEBGROUP = directors.round_robin();   <code style="color:red;font-size:20px">//使用new关键字创建director对象,使用round_robin算法</code>
        WEBGROUP.add_backend(websrv);
        WEBGROUP.add_backend(websrv2);
        WEBGROUP.add_backend(websrv);
        WEBGROUP.add_backend(websrv2);
}


sub vcl_recv {           <code style="color:red;font-size:20px">//接受请求子程序</code>

        set req.backend_hint = WEBGROUP.backend(); <code style="color:red;font-size:20px">//调用后端主机组</code>

        if (req.url ~ "(?i)\.(JPG|PNG|GIF)") {   <code style="color:red;font-size:20px">//对几种图片不进行缓存查找</code>
                return(pass);
        }

        if (req.restarts == 0) {     <code style="color:red;font-size:20px">//IP地址转移</code>
                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.method == "PURGE") {   <code style="color:red;font-size:20px">//对某个缓存对象进行清理操作</code>
                if (!client.ip ~ purgers) {
                        return (synth(405,"Purging not allowed for" + client.ip));
                }
        return (purge);    <code style="color:red;font-size:20px">//去往purge子程序操作</code>
        }

        if (req.method == "BAN") {     <code style="color:red;font-size:20px">//清理某一类缓存对象</code>
                if (!client.ip ~ purgers) {
                        return (synth(405,"Banning not allowd for" + client.ip));
                }
                ban("req.http.host == " + req.http.host + " && req.url == " + req.url);<code style="color:red;font-size:20px">//清除host+url的对象</code>
                return (synth(200,"Ban added."));    
        }

#       if (req.url ~ "(?i)\.php$") {      <code style="color:red;font-size:20px">//以.php请求至后端</code>
#               set req.backend_hint = websrv;
#       } else {
#               set req.backend_hint = default;
#       }
}


sub vcl_purge {    <code style="color:red;font-size:20px">//purge子程序</code>
        return (synth(200,"Purged"));<code style="color:red;font-size:20px">//合成信息,并返回值</code>
#       set req.method = "GET";<code style="color:red;font-size:20px">//将请求方法设置成GET</code>
#       return (restart);<code style="color:red;font-size:20px">//在发还给客户端,让客户端重新来取</code>

}



sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}


sub vcl_deliver {   <code style="color:red;font-size:20px">//发送给客户的数据报文</code>
    if (obj.hits>0) {   <code style="color:red;font-size:20px">//测试用,如果 有缓存,就把X-Cache首部信息发给客户端</code>
        set resp.http.X-Cache = "Hit via" + server.ip;
    } else {
        set resp.http.X-Cache = "Miss via" + server.ip;
    }
}
</pre>
<br /><br />


<p style="font-size:25px;color:green">varnish日志区域:
<br />
<style type="text/css">  
p{ text-indent:2em;}  
</style>
1、varnishstat - Varnish Cache statistics<br />
                
<p>            -1  //显示一次<br /></p>
<p>                -1 -f FILED_NAME </p>
<p>                -l:可用于-f选项指定的字段名称列表;</p>
                
<p>                MAIN.cache_hit </p>
<p>                MAIN.cache_miss</p>
                
<p>                # varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss</p>
<p>                # varnishstat -l -f MAIN -f MEMPOOL</p>
                
<p>            2、varnishtop - Varnish log entry ranking</p>
<p>                -1     Instead of a continously updated display, print the statistics once and exit.</p>
<p>                -i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;</p>
<p>                -I <[taglist:]regex></p>
<p>                -x taglist:排除列表</p>
<p>                -X  <[taglist:]regex></p>
                
<p>            3、varnishlog - Display Varnish logs</p>
                
<p>            4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format</p>

</p>

<code style="font-size:20px;color:green">systemctl start varnishncsa.service   //开启日志功能服务</code>









</ol>
</body>
</html>


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值