Varnish是一款高性能的缓存加速器,具有稳定,且效率更高,资源占用更少等特点。


缓存存储的格式:

    key-value:

        key:访问路径,URL, hash

         valueweb content       

    命中率:hit/(hit+miss)  

        文档命中率:从文档个数进行衡量;

        字节命中率:从内容大小进行衡量;

      注意:

           缓存对象:生命周期;定期清理;

        缓存空间耗尽:LRU(最近最少使用算法)

        可缓存对象,不可缓存对象(用户私有数据)

 

缓存处理的步骤:

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

 

新鲜度检测机制:

 1、  过期日期:

    Expires;例:Expires:Thu, 04 Jun 2015 23:38:18 GMT,是在这个时间以前都有效

    Cache-Control:max-age;例:Cache-Control:max-age=600,缓存有效时间为600s(秒)

 2、有效性再验证:revalidate,就是查到缓存以后,去向服务器端发送一个条件式请求,

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

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

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

 3、条件式请求首部:

    If-Modified-Since:基于请求内容的时间戳做验正;就是自从什么时间开始发生改变

    If-Unmodified-Since:自从什么时间开始没有发生改变

     If-Match:是否匹配

    If-None-Match:是否你匹配

       Etag:fdsfad9345,扩展标签,是校验码

 

浏览器发送一个请求,先经过缓存,如果缓存服务器没有,就会×××器端来响应,如果这个报文可以缓存,会缓存到缓存服务器,然后响应给浏览器;如果浏览器在发送一个相同的请求,如果缓存没有过期,就会从缓存服务器直接响应的

 

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

      varnish squid 

 

要想操作varnish,需要使用varnish的操作语言vclvcl的配置文件首先要被c编译器编译成二进制格式,然后才被varnish加载使用

vcl: Varnish Configuration Language,缓存策略配置接口;基于“域”的简单编程语言

varnish分为管理进程和子进程   

管理进程:编译VCL并应用新配置;监控vanish;初始化varnishCLI接口;

    子进程(Child/cache)包括:

       Acceptor:接收新的连接请求;

       workerthreads:处理用户请求;

       Expiry:清理缓存中的过期对象;

       Log/stats:日志相关的

     日志:Shared Memory Log,共享内存日志大小默认一般为90MB,分为两部分,前一部分为计数器,后一部分请求相关的数据;

 

varnish如何存储缓存对象:

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

    malloc:内存;

    persistent:基于文件的持久存储;在生产中是不可用的

 

  varnish的安装包在epel源中有提供,提供的是4.0版本的varnish,可以直接安装,

 

    varnish的配置文件为/etc/varnish/default.vcl

    varnish的命令行参数的配置文件/etc/varnish/varnish.params

    varnish的服务文件在/usr/lib/systemd/system/varnish.service

 

配置varnish的三种配置应用方式:

    1varnishd应用程序的命令行参数;(定义varnish主程序的工作特性)

        监听的socket, 使用的存储类型等等;额外的配置参数;

        -pparam=value :设置额外的参数

        -rparam,param,... : 设定只读参数列表;

        -fconfig:指定配置文件的,指到哪去读vcl配置文件的

        -aaddress[:port][,......]:指定服务监听的地址和端口的,可以指定多个,默认监听的端口是6081(提供服务的端口)和6082(管理接口)

        -s[name=]type[,options]:指定缓存使用哪一种存储机制的

        -Taddress[:port]:指定管理的地址和接口

        /etc/varnish/varnish.params:命令行参数的配置文件(CentOS7中常用)

 

    2-p选项指明的参数:(定义varnish各子进程或线程的工作特性)

         运行时参数:也可在程序运行中,通过其CLI进行配置;

 

    3vcl:配置缓存系统的缓存机制;(指明线程中的缓存功能的工作机制)

        通过vcl配置文件进行配置;

        先编译,后应用;依赖于c编译器;


下面以实例和和概念相结合的方式,讲述下varnish的相关知识和简单应用


172.16.249.195varnish所在的主机,

/etc/varnish/varnish.params文件中定义了varnish主程序的特性,即varnish启动时的参数

   VARNISH_VCL_CONF=/etc/varnish/default.vcl :定义了从哪读取vcl的配置

   VARNISH_LISTEN_PORT=6081:服务监听的端口,没指明地址代表所有地址

       VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:定义了管理的地址

   VARNISH_ADMIN_LISTEN_PORT=6082 :定义了管理的接口

   VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G":缓存的存储机制的定义

   VARNISH_TTL=120varnish联系后端服务器的超时时间

   ... ...

  

  修改缓存使用的机制,改为使用内存:VARNISH_STORAGE="malloc,128M"

 Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用

 提供一台主机启动httpd服务(172.16.249.115),提供测试页

for i in{1..10};do echo "Page $i on Web1" > /var/www/html/test$i.html;done

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_02

/etc/varnish/default.vcl文件中的是vcl的配置,

修改配置:

Varnish的相关知识,varnish的简单应用_以及资源分离_03

这一段是配置后端服务器地址和端口的

 

这样就可以启动varnish了(systemctl  start  varnish.service

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_04


可以看到启动成功了,访问测试一下,记得端口是6081

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_05

varnish的命令行工具:


   1varnishadm

    使用varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082,进入varnish的管理接口

        -S:指明密钥文件所在位置,-T:指明端口和IP地址

       进入后,使用help可以查看可以使用的命令

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_06

   ping:探测后端服务器是否在线

   status:显示子进程的工作状态

   vcl.list:显示所有可以使用的vcl文件,

   vcl.load <configname><filename>:编译vcl文件(filename),然后取一个名(configname

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_07


active:指正在使用的vcl配置文件

available:可用的vcl配置文件

vcl.use <configname>:切换使用的vcl文件

Varnish的相关知识,varnish的简单应用_以及资源分离_08

可以看到现在使用的就是test这个vcl文件了

 

vcl.discard <configname>:删除可用的vcl文件的

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_09

    param.show [-l] [<param>] :显示参数,

    param.show:显示所有的参数

        -l:显示详细的信息

     param.show<param>:只显示一个参数的信息

    param.set <param> <value>:设置参数的

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_10

storage.list:显示正在使用的缓存列表

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_11


vcl.show boot:可以显示boot文件编译以前的样子

Varnish的相关知识,varnish的简单应用_以及资源分离_12

backend.list:显示后端服务器列表的

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_13

   ban <field> <operator><arg> [&& <field> <oper> <arg>]...:清理缓存中的缓存对象

   ban.list:定义的ban规则的列表


  这可以动态装载vcl配置文件的,后续的很多操作都是在这个接口里操作的


   2Log

    varnishlog :显示日志信息的,需要访问一下,才会出内容的

    varnishncsa:这个也是显示日志信息的的,需要访问一下,才会出内容的

    这两个日志信息的显示格式不同,这两个命令行接口的使用,如有需要可以去网上搜索下

   3Top:排序后的信息

    varnishtop

   4Statistics:统计信息的

    varnishstat:显示缓存相关的信息

        -l:显示所有可以显示的字段

         这些字段中,常用的有:

            MAIN.cache_hit:缓存命中的次数

            MAIN.sess_conn:统计varnish已经处理过多少请求了

  MAIN.sess_drop:统计varnish已经丢弃过多少请求

   ... ...

       -f  NAME:只显示指定字段的信息

vcl:

   stateengine:各引擎之间存一定程度上的相关性;前一个engine如果可以有多种下游engine,则上游engine需要用return指明要转移的下游engine

   vcl_recv

   vcl_hash

   vcl_hit

   vcl_miss

   vcl_fetch

   vcl_deliver

   vcl_pipe

   vcl_pass

   vcl_error

 

  vcl编程语言语法:

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

    (2)sub $name: 用于定义子例程;

        subvcl_recv { }

    (3)不支持循环;

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

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

    (6)""专用;

    (7)操作符:=, ==, ~, !, &&, ||

        条件判断语句:

         if(CONDTION) {

          }else {

            }

      变量赋值:set  name=value

      撤销变量的值:unset  name

   varnish中常用的变量:

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

    req.http.X-Forwarded-For

    req.http.Auhtorization

    req.http.cookie

    req.request:请求方法

    client.ip:客户端IP

  vclv3)的工作机制流程图:

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_14

state engine workflow(v3):vclv3版本的引擎工作机制:

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

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

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

        vcl_recv--> vcl_pipe

vclv4)的工作机制流程图:

可以去这里查看https://www.varnish-software.com/book/4.0/_p_w_picpaths/simplified_fsm.svg

Varnish的相关知识,varnish的简单应用_以及资源分离_15

    state engine(v4)

        vcl_recv

        vcl_pass

        vcl_pipe

        vcl_hash

        vcl_hit

        vcl_miss

        vcl_backend_fetch

        vcl_backend_response

        vcl_backend_error

        vcl_purge

        vcl_synth

 state engine workflow(v4):vclv34版本的引擎工作机制跟v3类似,就不再多解释了

 

 下面演示操作vcl,实现一些简单应用:CentOS7中演示,使用的varnish4.0的版本


首先备份一份/etc/varnish/default.vcl,复制/etc/varnish/default.vcl/etc/varnish/test.vcl

修改/etc/varnish/test.vcl配置文件:

sub vcl_recv {}里面加入下面内容:

if (req.method == "PRI") {

       /* We do not support SPDY or HTTP/2.0 */

       return (synth(405));

    }

 

   if (req.method != "GET" &&

     req.method != "HEAD" &&

     req.method != "PUT" &&

     req.method != "POST" &&

      req.method != "TRACE" &&

     req.method != "OPTIONS" &&

     req.method != "DELETE") {

       /* Non-RFC2616 or CONNECT which is weird. */

       return (pipe);

    }

 

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

       /* We only deal with GET and HEAD by default */

       return (pass);

    }

   if (req.http.Authorization || req.http.Cookie) {

       /* Not cacheable by default */

       return (pass);

    }

  return (hash);

然后保存,使用varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082进入管理接口

然后使用vcl.load test1 test.vcl 装载刚在我们编写的配置文件,如果配置文件有错,会报错的;然后查看下vcl可用列表,使用vcl.use test1切换到test1

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_16

这定义的是一些默认的信息,没法测试,能加载成功就没问题了

下面修改test.vcl,在sub vcl_deliver {}中加入

if (obj.hits>0) {

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

    } else {

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

    }

这是自己定义的一个响应报文首部,如果命中就显示HIT,没命中显示MISSobj.hits是命中的次数

保存退出,然后在varnishadm接口下输入下面内容:

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_17


然后访问测试下:用一台虚拟机使用curl命令测试,-I选项是显示报文首部信息的

Varnish的相关知识,varnish的简单应用_以及资源分离_18

可以看到第一次请求是是没有缓存的,第二次就使用缓存了

 

varnish中的内置变量:

    变量种类:

        client

        server:是varnish本身相关的

        req:客户端发的请求

        resp:缓存服务器或代理服务器响应的

       bereq:是varnish往后端服务器请求的

        beresp:后端服务器响应过来的内容

        obj:后段服务器响应过来的内容或者从缓存中取得的内容的属性

        storage:缓存存储有效性的

    bereq

       bereq.http.HEADERS:varnish发往backend server的请求报文的指定首部;

       bereq.request:请求方法;

      bereq.url:请求的url

      bereq.proto:使用的协议版本

      bereq.backend:指明要调用的后端主机;

    beresp

      beresp.proto:使用的协议版本

      beresp.status:后端服务器的响应的状态码

      beresp.reason:原因短语;

      beresp.backend.ip:后端服务器的ip地址

      beresp.backend.name:后端服务器的主机名称

      beresp.http.HEADER:backend server响应的报文的首部;

      beresp.ttl:后端服务器响应的内容的余下的生存时长;

    obj

      obj.ttl:对象的ttl值;

       obj.hits:此对象从缓存中命中的次数;

    server

      server.ip:缓存服务器自己的ip地址

      server.hostname:缓存服务器自己的主机名

    req 

      rep.http

      rep.url

      ......

    resp

resp.http

resp.status

 ... ...

    storage

      storage.<name>.free_space:缓存空间的空闲空间大小

      storage.<name>.use_space:缓存空间的已用空间大小

      storage.<name>.happy:缓存是否还有效

    Functions(函数)

      banexpression):清理缓存的

      return()

      new()

      regsubstrregexsub):正则表达式替换,把str替换为sub,但只替换第一次出现的

regsuballstrregexsub):正则表达式替换,把str替换为sub,替换所有的

 

  详细的varnish的内置变量等可以查看官方文档:

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

 

在刚才的test.vcl配置文件中修改,在sub vcl_deliver{}中修改如下:

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_19

然后在加载,使用

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_20

测试下

Varnish的相关知识,varnish的简单应用_以及资源分离_21

可以看到使用成功了

 

示例:强制对某资源的请求,不检查缓存

 

修改test.vcl如下,在sub vcl_recv {}里加入:

if (req.url ~ "^/test7.html$") {

        return(pass);

    }

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_22

然后在varnishadm命令行接口中做,vcl.loadvcl.use

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_23

然后做测试,首先请求其他资源,可以看到能使用缓存

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_24

然后请求test7.html

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_25

可以看到没有使用缓存

 

 

  强制对下面两类资源的请求,不检查缓存;

    /admin

    /login

修改test.vcl配置文件,修改配置文件的sub vcl_recv {},修改为如下:

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

        return(pass);

     }

然后在后端的服务器的/var/www/html目录下,创建每一个admin目录,然后提供测试页,然后在varnishadm命令行接口中做,vcl.loadvcl.use,在测试可以看到不缓存。这里就不再演示了,跟上面的类似。

 

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

 

修改test.vcl配置文件,在vcl_backend_response{}中,加入下面这些内容:

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

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

        setberesp.ttl = 3600s;

        unsetberesp.http.Set-Cookie;

    }

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

    setberesp.ttl = 600s;

    unsetberesp.http.Set-Cookie;

     }

}

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_26

然后在varnishadm命令行接口中做,vcl.loadvcl.use

Varnish的相关知识,varnish的简单应用_以及资源分离_27

然后在后端主机上加载一个图片,在/var/www/html目录下,下载1.jpg2.jpg的图片

然后在访问测试下,因为首部显示的不全,一般默认缓存一会就结束了,我们在里面定义的是定义的是3600s,这个缓存是缓存在varnish中,所以一个小时内请求这个资源都会使用缓存

Varnish的相关知识,varnish的简单应用_以及资源分离_28

等几分钟,然后在访问这个资源,会发现还是使用缓存

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_29

这样就做好了,就是不太容易看出效果,

 

  backend server的定义:

    backendname {

        .attribute = "value";

     }       

        .host:backend主机的IP

        .portbackend主机监听的PORT

        .probe:backend做健康状态检测;

           .probe = {...}

        .max_connections:并连接最大数量;

         

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

    probename {

      .attribute = "value";

       }       

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

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

 

示例:做两个后端服务器,然后做健康状态检测,再做下分离,让访问图片资源的调度到一台后端服务器上,访问其他资源的调度到令一台后端主机上

修改test.vcl配置文件,如下:

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_30

然后在varnishadm命令行接口中做,vcl.loadvcl.use

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_31

然后打开另一个虚拟机(172.16.249.159)设置测试页,for i in {1..10};do echo "Page $i in Web2" >/var/www/html/test$i.html ;done,这个主机里没有图片

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_32

varnishadm命令行接口中,使用backend.list,可以查看到后端服务器的信息和状态

Varnish的相关知识,varnish的简单应用_以及资源分离_33

访问测试

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_34

Varnish的相关知识,varnish的简单应用_以及资源分离_35

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_36



可以看到图片资源的是发送给web1主机(172.16.249.115)了,请求的.html资源的是发送给web2主机(172.16.249.159)了

 

示例:实现负载均衡

 

修改test.vcl配置文件:

Varnish的相关知识,varnish的简单应用_以及资源分离_37

这样负载均衡就定义好了,但是这样不好查看效果,因为有缓存,为了演示效果加入

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_38

就是访问test7.html时不让缓存,这样访问时就可以看到负载均衡效果了

然后在varnishadm命令行接口中做,vcl.loadvcl.use

访问测试

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_39

可以看懂访问test7.html时是负载均衡,访问其他资源时,是使用的缓存,所以不会变

 

或者使用这个方式测试,每次使用一个新资源范围,也可以看到负载均衡效果

Varnish的相关知识,varnish的简单应用_varnish的基础知识和简单应用_40

直接在物理机中测试也行,物理机中的浏览器访问时是不允许缓存的,所以可以看到负载均衡效果,如果你的物理机的浏览器对这些资源是允许缓存的话,就只能用上面的方法定义一个资源,让它不缓存

Varnish的相关知识,varnish的简单应用_以及资源分离_41

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_42

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_43

Varnish的相关知识,varnish的简单应用_以及使用varnish做负载均衡_44

可以负载均衡

这样负载均衡就做好了

 

如果有不明白的配置可以到这个连接下去查看varnish的官方配置示例:https://www.varnish-cache.org/trac/wiki/VCLExamples