Varnish基础原理及简单配置

来源:互联网 发布:怎样辨别淘宝评论真假 编辑:程序博客网 时间:2024/06/05 23:53
 <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      Probewebsrv(172.16.252.113,,80)     4      probe      Sick 5/8   //检测出来的效果sick生病了default(127.0.0.1,,8080)       4      probe      Healthy (no probe)backend.list200        Backend name                   Refs   Admin      Probewebsrv(172.16.252.113,,80)     4      probe      Sick 4/8default(127.0.0.1,,8080)       4      probe      Healthy (no probe)backend.list200        </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.vclvcl.use test1 也可在此操作清除缓存:ban req.url ~ .js$    //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便客户端操作:<code style="color:green">~]# crul -I http://172.16.254.35</code>HTTP/1.1 200 OKServer: nginx/1.10.2Date: Tue, 27 Jun 2017 09:27:38 GMTContent-Type: text/htmlContent-Length: 17Last-Modified: Tue, 27 Jun 2017 06:21:47 GMTETag: "5951f97b-11"X-Varnish: 3964978Age: 0Via: 1.1 varnish-v4X-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      Probewebsrv(172.16.252.113,,80)     4      probe      Sick 5/8   //检测出来的效果sick生病了default(127.0.0.1,,8080)       4      probe      Healthy (no probe)backend.list200        Backend name                   Refs   Admin      Probewebsrv(172.16.252.113,,80)     4      probe      Sick 4/8default(127.0.0.1,,8080)       4      probe      Healthy (no probe)backend.list200        </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.vclvcl.use test1 也可在此操作清除缓存:ban req.url ~ .js$    //清除以.js结尾的文件缓存,毕竟可以用正则表达式,多方便客户端操作:<code style="color:green">~]# crul -I http://172.16.254.35</code>HTTP/1.1 200 OKServer: nginx/1.10.2Date: Tue, 27 Jun 2017 09:27:38 GMTContent-Type: text/htmlContent-Length: 17Last-Modified: Tue, 27 Jun 2017 06:21:47 GMTETag: "5951f97b-11"X-Varnish: 3964978Age: 0Via: 1.1 varnish-v4X-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>

 
原创粉丝点击