无心写博客

varnish

varnish

web cache

  1. 程序的局部性特征

     - 时间局部性:刚刚访问过的数据,在很短的时间内会被再次访问到。
     - 空间局部性:一个数据如果被访问到了,则它周边的数据也可能被访问到。
    
  2. 设备层级衔接方式

     - 两个设备间衔接不上,加用中间层,如缓存
    
  3. 什么是缓存命中?

     - 从缓存中找到了需要的数据
    
  4. 什么是命中率?

     - 命中资源数hit/(命中资源数hit+miss资源数),分两类
         - 页面命中率:基于页面数量进行衡量
         - 字节命中率:基于页面的体积进行衡量
    
  5. 与缓存相关的首部

     - Expires:定义响应资源的过期时间,绝对时间标记,简单粗暴
     - Cache-Control:请求报文和响应报文缓存控制
     - Etag:资源标签
     - If-None-Match:资源标签是否改变
     - Last-Modified:最后一次修改时间
     - If-Modified-Since:缓存时的时间戳
     - Vary
     - Age
    
  6. Cache-Control控制项

  7. HTTP Validation条件式请求,检查缓存项和原始服务器资源内容是否一致

     - Last Modified/If-Modified-Since
         - 请求服务器使用If-Modified-since,从此缓存时间戳,与原始服务器上是否匹配,如果改变,直接响应(200)
         - 若没变,last-modified (304),不适用变化频繁的资源
     - Etag/If-None-Match
         - 给同样内容加一个标签Etag,内容改变时Etag标签也会改变,
         - 请求服务器使用If-None-Match向http服务器询问标签是不是不匹配,若匹配则响应not modifyed(304),
         - 否则http服务器直接响应(200)
     - 相对时间和检查机制结合使用 
         - 在缓存有效期内从缓存响应,过期后去服务器检查资源是否更新
    

varnish

  1. 缓存开源解决方案

         - varnish
             - 充分利用epoll机制(能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率),并发量大,单连接资源较轻
         - squid
             - 在较大并发下,稳点性好,老当益壮
    
  2. 什么是varnish

     - varnish是一个轻量级的Cache和反向代理软件,通常只为httpd提供缓存
    
  3. varnish架构

     - 主要由核心守护进程varnishd组成
         - Manager Process
             - 管理进程,相当于nginx的主控进程,不处理用户请求
         - Cacher Process
             - 线程Storage:完成缓存存储管理
             - 线程Log/Stats:日志记录----->存入共享内存Shared Memory Log中
             - 线程Worker threads:真正处理用户请求,通过线程池来定义,最大并发(线程池*线程池最大并发)
         - shared memory log
             - varnishlog:读取日志文件,保存在磁盘中
             - varnishstat:读取统计数据,计数器    
         - VCL配置接口:varnish配置语言
         - varnishadm:让varnish加载新配置文件
         - VCC Process:varnish的c编译器
    
  4. 安装(centos 7中varnish被收入epel仓库)

     - [root@ _1_ ~]# yum -y install varnish
    
  5. 程序环境

     配置文件:
         - /etc/varnish/varnish.params(/etc/sysconfig/varnishd):配置varnish服务进程的工作特性(监听地址和端口,缓存机制等)
         - /etc/varnish/default.vcl:配置各Child/Cache线程的工作特性
     主程序:
         - /usr/sbin/varnishd
     CLI interface:
         - /usr/bin/varnishadmin:通过此管理工具,完成与Manager Process的交互,进而控制varnish的工作特性
     Share Memory Log交互工具:
         - /usr/bin/varnishhist:日志历史
         - /usr/binvarnishlog:记录详细log(请求报文首部,响应报文首部等)
         - /usr/bin/varnishcsa:格式化记录日志
         - /usr/bin/varnishstat:日志统计
         - /usr/bin/varnishtop:日志排序分析
     测试工具程序:
         - /usr/bin/varnishtest
     VCL配置文件重载程序:
         - /usr/sbin/varnish_reload_vcl:此程序会编译配置文件
     Systemd Unit File:
         - /usr/lib/systemd/system/varnish.service:varnish服务
         - /usr/lib/systemd/system/varnishlog.service:原始记录日志(保存磁在盘上)
         - /usr/lib/systemd/system/varnishncsa.service:ncsa格式日志(保存磁在盘上)
    
  6. varnish的缓存存储机制(Storage Types):

     - malloc[,size]:内存存储,[,size]用于定义空间大小,重启后所有缓存项失效
     - file[,path[,size[,granularity]]]:文件存储,黑盒,重启后所有缓存项失效
     - persistent,path,size:文件存储,黑盒,重启后所有缓存项有效(试验阶段)
    
  7. varnish的程序选项

     - 程序选项:/etc/varnish/varnish.params文件;
         - -a address[:port][,address[:port][...]:默认为6081端口;
         - -T address[:port]:默认为6082端口;
         - -s [name=]type[,options]:定义缓存存储机制;
         - -u user
         - -g group
         - -f config:VCL配置文件;
         - -F:运行于前台;
     - 运行时参数:/etc/varnish/varnish.params文件, DEAMON_OPTS
         - DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
         - -p param=value:设定运行参数及其值,可重复使用多次
         - -r param[,param...]:设定指定的参数为只读状态
    
  8. 重载vcl配置文件:

         - ~]# varnish_reload_vcl
    
  9. varnishadm管理工具

     连接:
         - ~]# varnishadm -S /etc    /varnish/secret -T [ADDRESS:]PORT
     配置文件相关:
         - vcl.list:查看所有编译过的配置文件
         - vcl.load <configname> <filename>:装载,加载并编译
         - vcl.use <configname>:激活
         - vcl.discard <configname>:删除配置文件
     运行时参数:
         - param.show -l:显示列表
         - param.show <PARAM> 显示指定PARAM参数
         - param.set <PARAM> <VALUE> 设置PARAM的值
    
     缓存存储:
         - storage.list
     后端服务器:
         - backend.list
    
  10. 缓存流程图解

    - 一个请求进入,varnish收下这个请求,判断是否对这个请求做处理
        - 访问控制,直接拒绝
        - 请求方法不识别,直接找后端服务器响应
        - 正常请求,进入下一步
    - 查询此请求方法是否能缓存
        - 不能缓存(如post,put),交给vcl_fetcg,由vcl_fetch投递给后端服务器响应
        - 能缓存,进入下一步
    - vcl_hash基于hash查找缓存中是否有对应资源
        - 如果命中,从本地缓存中直接响应给客户端
        - 若未命中,通过vcl_fetch到后端服务器取回资源,然后先缓存,再响应给客户端
    
  11. VCL状态引擎切换
    - vcl_recv收到请求,查找vcl_hash
        - 若命中(传递值hit),交由vcl_hit
            - hit命中,直接从缓存中响应,交由vcl_deliver投递给客户端
            - vcl_hash -(hit)-> vcl_hit --> vcl_deliver
        - 未命中(传递值miss),交由vcl_miss
            - 交由vcl_backend_fetch请求后端服务器
            - vcl_hash -(miss)-> vcl_miss --> vcl_backend_fetch --> vcl_backend_response --> vcl_deliver
        - 若要删除缓存项(传递值purge),交由vcl_purge
            - 交由vcl_synh管理缓存,删除对应缓存
            - vcl_hash -(purge)-> vcl_purge --> vcl_synth
        - 若不能理解请求(传递值pipe),交由vcl_pipe,请求被直接送至后端服务器
            - vcl_hash -(pipe)-> vcl_pipe
        - 并发连接超出(传递值busy),进入waiting状态,会等待重新请求查询缓存
        - 传递值(pass,hit-for-pass),交由vcl_pass
        - vcl_hit和vcl_miss也能交由给pass
    - 两个特殊引擎:
        - vcl_init:在处理任何请求之前要执行的vcl代码:主要用于初始化vMODS
        - vcl_fini:所有的请求都已经结束,在vcl配置被丢弃时调用,主要用于清理vMODS
    

VCL语法(4.0)

  1. 语法格式

     - 文件开始要注明vcl版本号:vcl 4.0;
     - //,#,/*,*/为注释
     - 子例行Subroutines使用sub关键字;例如sub_recv {...};
     - 不支持循环,但支持条件语法,支持內建变量(受限于引擎)
     - 使用一个keyword基于return函数终止当前状态引擎,并决定交给哪一个状态引擎
     - “域”专用配置,在一个状态引擎中的配置只对当前状态引擎有效
    
  2. VCL Finite State MAchine

     - 每一个请求被单独处理
     - 请求和请求间任何时间都是隔离的
     - 各状态引擎有相关性,通过return连接
     - 內建VCL code一直有效,并附加在自建的代码之后(vcl.show -v boot)
    
  3. 三类主要语法

     - sub subroutine {
             ...
         }
     - if CONDITION {
             ...
         } else {    
             ...
         }
     - return(), hash_data()
    
  4. 內建函数和keyword

     函数:
         regsub(str,regex,sub):字符串为str,根据正则regex模式匹配,把匹配到的内容替换为sub,只替换一次
         regsuball(str,regex,sub):和regsub相同,替换所有
         ban(boolean expression):符合表达式的都清理
         hash_data(input):对input做hash计算
         synthetic:
     Keywords:
         call subrouting:调用子例行程序
         return(action):指明下一个动作
         new:
         set:设定变量的值
         unset:取消变量的值
     布尔型表达式操作符:
         ==,!=,~,>,>=,<,<=
         逻辑操作符:&&,||,!
         变量赋值:=
    
  5. 例:若通过缓存响应给客户端,在响应首部添加X-Cache,并设置值

     在deliver段中添加条件判断
                 sub vcl_deliver {
             # Happens when we have all the pieces we need, and are about to send the
             # response to the client.
             #
             # You can do accounting or modifying the final object here.
             if (obj.hits>0) {
                 set resp.http.X-Cache = "HIT via " + server.ip;
             } else {
                 set resp.http.X-Cache = "MISS via " + server.ip;
             }
         }
     重新加载配置文件
         [root@ _18_ /etc/varnish]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
         varnish> vcl.load conf1 default.vcl 
         200        
         VCL compiled.
    
         vcl.list
         200
         active             0 boot
         available       0 conf1
    
         vcl.use conf1
         200        
         VCL 'conf1' now active
    
         varnish> vcl.list
         200        
         available       0 boot
         active          0 conf1
    
  6. 客户端第一次访问,响应码为200,资源由web服务器返回。X-Cache为MISS

  7. 客户端第二次访问,响应码340,资源由缓存服务器返回。X-Cache为HIT

  8. 变量类型


  9. 示例:URL中带有login或admin的字符串不检查缓存

                 sub vcl_recv {
             # Happens before we check if we have this in cache already.
             #
             # Typically you clean up the request here, removing cookies you don't need,
             # rewriting the request, etc.
             if (req.url ~ "(?i)^/(login|admin)") {   #(?!)为正则表达式模式标志位,i为不区分大小写
                 return(pass);
             }
         }
     第一次访问:X-Cache值为MISS
         Request URL:http://192.168.100.73/admin/
         Request Method:GET
         Status Code:304 Not Modified
         Remote Address:192.168.100.73:80
    
         Age:0
         Connection:keep-alive
         Date:Wed, 02 Nov 2016 02:41:24 GMT
         ETag:"e0102-6-5403f450439af"
         Server:Apache/2.2.15 (CentOS)
         Via:1.1 varnish-v4
         X-Cache:MISS via 192.168.100.73
         X-Varnish:33
     第二次访问,X-Cache的值依然为MISS,varnish并未通过缓存响应
         Request URL:http://192.168.100.73/admin/
         Request Method:GET
         Status Code:304 Not Modified
         Remote Address:192.168.100.73:80
         Response Headers
         view source
         Age:0
         Connection:keep-alive
         Date:Wed, 02 Nov 2016 02:50:04 GMT
         ETag:"e0102-6-5403f450439af"
         Server:Apache/2.2.15 (CentOS)
         Via:1.1 varnish-v4
         X-Cache:MISS via 192.168.100.73
         X-Varnish:32780
    
  10. 对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长;

    if (beresp.http.cache-control !~ "s-maxage") {
            if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") {
                unset beresp.http.Set-Cookie;
                set beresp.ttl = 3600s;
            }
        }
    
  11. 缓存对象的修剪:purge,ban (purge:对某特定资源清理缓存,ban:清理符合条件的缓存)

    执行purge操作:
        sub vcl_purge {
            return (synth(200,"Purged"));    #vcl_purge清理缓存,调用synth,合成响应报文
    
    客户端第一次请求
        [root@ _26_ /etc/varnish]# curl -I http://192.168.100.73
        HTTP/1.1 200 OK
        Date: Sat, 12 Nov 2016 10:44:03 GMT
        Server: Apache/2.2.15 (CentOS)
        Last-Modified: Tue, 01 Nov 2016 15:50:24 GMT
        ETag: "e0104-7-5403f48611496"
        Content-Length: 7
        Content-Type: text/html; charset=UTF-8
        X-Varnish: 65552 65548
        Age: 4
        Via: 1.1 varnish-v4
        X-Cache: MISS via 192.168.100.73
        Connection: keep-alive
    
    客户端第二次请求:
        [root@ _23_ /etc/varnish]# curl -I http://192.168.100.73
        HTTP/1.1 200 OK
        Date: Sat, 12 Nov 2016 10:44:03 GMT
        Server: Apache/2.2.15 (CentOS)
        Last-Modified: Tue, 01 Nov 2016 15:50:24 GMT
        ETag: "e0104-7-5403f48611496"
        Content-Length: 7
        Content-Type: text/html; charset=UTF-8
        X-Varnish: 32780 65548
        Age: 1
        Via: 1.1 varnish-v4
        X-Cache: HIT via 192.168.100.73
        Connection: keep-alive
    
    客户端使用PURGE请求:
        [root@ _27_ /etc/varnish]# curl -X PURGE -I http://192.168.100.73
        HTTP/1.1 501 Method Not Implemented
        Date: Sat, 12 Nov 2016 10:54:01 GMT
        Server: Apache/2.2.15 (CentOS)
        Allow: GET,HEAD,POST,OPTIONS,TRACE
        Content-Length: 297
        Connection: close
        Content-Type: text/html; charset=iso-8859-1
    
    客户端再次请求:显示X-Cache为MISS,达到了清理缓存的效果
    
        [root@ _28_ /etc/varnish]# curl -I http://192.168.100.73
        HTTP/1.1 200 OK
        Date: Sat, 12 Nov 2016 10:54:32 GMT
        Server: Apache/2.2.15 (CentOS)
        Last-Modified: Tue, 01 Nov 2016 15:50:24 GMT
        ETag: "e0104-7-5403f48611496"
        Content-Length: 7
        Content-Type: text/html; charset=UTF-8
        X-Varnish: 65554
        Age: 0
        Via: 1.1 varnish-v4
        X-Cache: MISS via 192.168.100.73
        Connection: keep-alive
    
  12. 何时执行purge操作

    sub vcl_recv {
        if(req.method == "PURGE") {
            return(purge);
        }
    }
    
  13. 添加purge请求的访问控制法则

        acl purges {
            "127.0.0.0"/8;
            "10.1.0.0"/16;
        }
    
        sub vcl_recv {
            if(req.method == "PURGE") {
                if(client.ip ~ purges) {
                    return(synth(405,"Purging not allowed for" + client.ip))    
                }
            }
        }
    
    其他客户端访问,被拒绝
        [root@ _4_ ~]# curl -X PURGE http://192.168.100.73
        <!DOCTYPE html>
        <html>
          <head>
            <title>405 not allowed purge method for 192.168.100.63</title>
          </head>
          <body>
            <h1>Error 405 not allowed purge method for 192.168.100.63</h1>
            <p>not allowed purge method for 192.168.100.63</p>
            <h3>Guru Meditation:</h3>
            <p>XID: 32820</p>
            <hr>
            <p>Varnish cache server</p>
          </body>
        </html>
    
    本机访问,purge成功:
        [root@ _54_ /etc/varnish]# curl -X PURGE http://127.0.0.1
        <!DOCTYPE html>
        <html>
          <head>
            <title>200 purged</title>
          </head>
          <body>
            <h1>Error 200 purged</h1>
            <p>purged</p>
            <h3>Guru Meditation:</h3>
            <p>XID: 65572</p>
            <hr>
            <p>Varnish cache server</p>
          </body>
        </html>
    
  1. 设定使用多个后端主机:

    backend default {
        .host = "192.168.100.63";
        .port = "80";
    }
    
    backend appsrv {
            .host = "192.168.100.62";
        }
    
    sub vcl_recv {
        if (req.url ~ "(?i)\.php$") {
            set req.backend_hint = appsrv;
        } else {
            set req.backend_hint = default;
        }
    }
    
    Director:调度
        varnish module; 
            使用前需要导入:
                import director;
    
        示例:
            import directors;    # load the directors
    
            backend server1 {
                .host = 
                .port = 
            }
            backend server2 {
                .host = 
                .port = 
            }
    
            sub vcl_init {
                new GROUP_NAME = directors.round_robin();
                GROUP_NAME.add_backend(server1);
                GROUP_NAME.add_backend(server2);
            }
    
            sub vcl_recv {
                set req.backend_hint = GROUP_NAME.backend();
            }
    
  1. 健康状态检测

    BE Health Check:
        backend BE_NAME {
            .host =  
            .port = 
            .probe = {
                .url= 
                .timeout= 
                .interval= 
                .window=
                .threshhold=
            }
        }
    .probe:定义健康状态检测方法;
            .url:检测时请求的URL,默认为”/"; 
            .request:发出的具体请求;
                .request = 
                    "GET /.healthtest.html HTTP/1.1"
                    "Host: www.magedu.com"
                    "Connection: close"
            .window:基于最近的多少次检查来判断其健康状态; 
            .threshhold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;
            .interval:检测频度; 
            .timeout:超时时长;
            .expected_response:期望的响应码,默认为200;
    
    健康状态检测的配置方式:
            (1) probe PB_NAME = { }
                 backend NAME = {
                .probe = PB_NAME;
                ...
                 }
    
            (2) backend NAME  {
                .probe = {
                    ...
                }
            }
    
    示例:
            probe check {
                .url = "/.healthcheck.html";
                .window = 5;
                .threshold = 4;
                .interval = 2s;
                .timeout = 1s;
            }
    
            backend default {
                .host = "10.1.0.68";
                .port = "80";
                .probe = check;
            }
    
            backend appsrv {
                .host = "10.1.0.69";
                .port = "80";
                .probe = check;
            }    
    
    使用管理工具设定健康状态:
        backend.set_health appsrv healthy|sick
    

varnish的参数

  1. 线程相关的参数:

     在线程池内部,其每一个请求由一个线程来处理; 其worker线程的最大数决定了varnish的并发响应能力
         thread_pools:Number of worker thread pools. 线程池数量,最好小于或等于CPU核心数量; 
         thread_pool_max:The maximum number of worker threads in each pool.最大并发连接数
         thread_pool_min:The minimum number of worker threads in each pool. 额外意义为“最大空闲线程数    
         最大并发连接数=thread_pools  * thread_pool_max
    
         thread_pool_timeout:线程空闲超时时长,保留为最大空闲进程数
         thread_pool_add_delay:创建线程延时
         thread_pool_destroy_delay:销毁进程延时
    
     设置方式:
         vcl.param
         param.set thread_pool_max 1024
    
     永久有效的方法:
         varnish.params
         DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"    
    
  2. 日志区域

     varnishstat 缓存相关状态日志
         -1 只显示一次,不动态刷新 
         -l:显示所有字段名
         -f:指定字段名
         例:varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
    
     varnishtop 缓存实时日志排序显示
         -1 
         -i taglist标签
         -I <[taglist:]regex> 可以同时使用多个-i选项,也可以一个选项跟上多个标签
         -x taglist:排除列表
         -X  <[taglist:]regex>
    
     varnishlog 实时详细josn格式日志
     varnishncsa 实时常规日志输出
    
  3. 内建函数

     hash_data():指明哈希计算的数据;减少差异,以提升命中率;
         regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite
         regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;
         return():
         ban(expression) 
         ban_url(regex):Bans所有的其URL可以被此处的regex匹配到的缓存对象;
         synth(status,"STRING"):purge操作;
    

总结

    varnish 4.0:子例程
            vcl_init         定义服务器组,初始化
            vcl_recv        接收和处理请求,当请求到达并成功接收后被调用,判断请求数据决定如何处理
            vcl_hash         hash用户请求,判断是否查缓存,(早期先判断,是否查缓存,再hash)
            vcl_hit         缓存命中,在执行lookup指令后,在缓存中找到的请求内容将自动调用该函数
            vcl_pass        在此状态下,会直接进入后端请求,即进入fetch(vcl_fetch)状态
            vcl_miss         缓存中没有找到请求内容时调用此函数,判断是否需要从后端服务器获取内容
            vcl_pipe         不理解请求,将请求直接传递后端主机,并将后端响应原样返回客户端
            vcl_waiting        操作忙,送至此
            vcl_purge         清理缓存
            vcl_deliver        投递给客户端
            vcl_synth        合成响应报文
            vcl_fini        清理清理定义内容

            vcl_backend_fetch    对请求进行后端获取,发送请求,获得数据,根据设置进行本地存    
            vcl_backend_response 获得后端主机的响应后,可调用此函数
            vcl_backend_error  从后端主机获取源文件失败时,调用此函数

        sub VCL_STATE_ENGINE     定义状态引擎(4.0级以后 默认状态附加在配置之后)
        backend BE_NAME {}         定义后端主机
        probe PB_NAME {}         定义健康状态监测
        acl ACL_NAME {}            定义访问控制

posted on 2016-11-16 14:25  无心写博客  阅读(252)  评论(0)    收藏  举报

导航