Varnish--知识总结

关于Varnish

Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的 squid 相比,varnish 具有性能更高、速度更快、管理更加方便等诸多优点,很多大型的网站都开始尝试使用 varnish 来替换 squid,这些都促进 varnish 迅速发展起来。挪威的最大的在线报纸 Verdens Gang(vg.no) 使用 3 台 Varnish 代替了原来的 12 台 Squid,性能比以前更好,这是 Varnish 最成功的应用案例。

1、varnish系统架构

varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)

Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。

这里写图片描述

Child进程包含多种类型的线程,常见的如:

  • Acceptor线程:接收新的连接请求并响应;
  • Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多;
  • Expiry线程:从缓存中清理过期内容;

Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session工作区。

2、varnish日志

为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存。

共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。

3、VCL

Varnish Configuration Language (VCL)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。

VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。

4、varnish的后端存储

varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:

  1. file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);
  2. malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;
  3. persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;

varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。

选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。然而,需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。

为varnishd指定使用的缓存类型时,-s选项可接受的参数格式如下:
malloc[,size] 或
file[,path[,size[,granularity]]] 或
persistent,path,size {experimental}

file中的granularity用于设定缓存空间分配单位,默认单位是字节,所有其它的大小都会被圆整。

engine state

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

 state engine:
         vcl_recv
         vcl_hash
         vcl_hit
         vcl_miss
         vcl_fetch
         vcl_deliver
         vcl_pipe
         vcl_pass
         vcl_error

这里写图片描述

state engine workflow:
    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

Varnish工作流程

这里写图片描述

图中红色的线条:没有查询缓存/缓存中数据过期/缓存中没有数据 情况下的流程

图中*的线条:直接将匹配数据通过内置函数vcl_pipe送往后台主机的流程

图中绿色的线条:查询缓存数据命中且数据没有过期/经后台主机返回的数据经被缓存后返回给客户流程

图中蓝色的线条:数据没有命中缓存向后台主机发出查询的流程

图中黑色的线条:数据从后台主机返回给varnish缓存的流程

图中内置函数的作用:

4.1)vcl_recv:用于接收和处理请求,请求到达并被成功接受后被调用。

四个主要用途:

    修改客户端请求数据减少缓存对象差异性:比如删除URL中的www.字符

    基于客户端数据选用缓存策略:不如不缓存POST请求,

    为web应用程序执行URL重写规则

    挑选合适的后端服务器

经常使用的终止语句:

    pass:绕过缓存,不从缓存中查询内容或不将内容存储至缓存

    pipe:不对客户端进行检查或做出任何操作,而是在客户端与后台服务间建立“管道“进行数据传输。

    lookup:在缓存中查找用户请求的对象

    error :格式:error code [reason] ,向客户端返回一个错误代码code 和 原因resion,该reason可自定义

4.2)vcl_pipe:将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容传递给客户端,直到这个链接被关闭。

经常使用的终止语句:

    pipe:说明见上

    error code [reason]:说明见上

4.3)vcl_hash: 在缓存中进行查询

4.4)vcl_hit:在缓存中找到请求的内容

 经常使用的终止语句:

    deliver:将找到的内容发送给客户端,把控制权交个函数vcl_deliver

    error code [reason]:说明见上

    pass:将控制权交个vcl_pass函数处理,可能是缓存中数据过期所致

4.5)vcl_miss:当在缓存中没有找到匹配数据时被调用

 经常使用的结束语:

    error code [reason]:说明见上

    pass:说明见上

    fetch:表示从后端获取的请求的内容,并将控制权交给VCL_fetch函数

4.6)vcl_pass:将请求直接传递给后端主机,后端主机将应答数据发送给客户端,而不执行缓存,每次都返回最新内容。

 经常使用的结束语:

    error code [reason]:说明见上

    fetch:说明见上

4.7)vcl_fetch:向后端主机获取内容,通过判断将内容放入缓存,还是直接返回给客户端。

 经常用的结束语:

    error code [reason]:说明见上

    deliver:将控制器交给vcl_deliver函数,将数据返回给客户端

    hit_no_pass:不缓存数据,直接返回给客户端

4.8)vcl_deliver函数:将缓存中找到的数据返回给客户端

 经常使用的结束语:

    error code [reason]:说明见上

    deliver:将内容返回给客户端

代码示例:

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);
                }               


            定义在vcl_deliver中,向响应给客户端的报文添加一个自定义首部X-Cache;
                if (obj.hits>0) {
                    set resp.http.X-Cache = "HIT";
                } else {
                    set resp.http.X-Cahce = "MISS";
                }

varnish中的内置变量:

变量种类:
    client
    server
    req
    resp
    bereq
    beresp
    obj
    storage

    bereq
        bereq.http.HEADERS: 由varnish发往backend server的请求报文的指定首部;
        bereq.request:请求方法;
        bereq.url:
        bereq.proto:
        bereq.backend:指明要调用的后端主机;

    beresp
        beresp.proto
        beresp.status:后端服务器的响应的状态码
        beresp.reason:原因短语;
        beresp.backend.ip
        beresp.backend.name
        beresp.http.HEADER: 从backend server响应的报文的首部;
        beresp.ttl:后端服务器响应的内容的余下的生存时长;

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

    server
        server.ip
        server.hostname
    req
    resp
支持虚拟主机:

        if (req.http.host == "www.magedu.com") {

        }

backend server的定义:

backend name {
            .attribute = "value";
        }   

        .host: BE主机的IP;
        .port:BE主机监听的PORT;

        .probe: 对BE做健康状态检测;
        .max_connections:并连接最大数量;

    **后端主机的健康状态检测方式**:
        probe name {
             .attribute = "value";
        }   

        .url: 判定BE健康与否要请求的url; 
        .expected_response:期望响应状态码;默认为200;

        示例1:
            backend websrv1 {
                .host = "172.16.100.68";
                .port = "80";
                .probe = {
                    .url = "/test1.html";
                }
            }

            backend websrv2 {
                .host = "172.16.100.69";
                .port = "80";
                .probe = {
                    .url = "/test1.html";
                }
            }

            sub vcl_recv {
                if (req.url ~ "(?i)\.(jpg|png|gif)$") {
                    set req.backend_hint = websrv1;
                } else {
                    set req.backend_hint = websrv2;
                }               
            }

        示例2:
        对请求进行负载均衡
            import directors;

            sub vcl_init {
                new mycluster = directors.round_robin();
                mycluster.add_backend(websrv1);
                mycluster.add_backend(websrv2);
            }

            vcl_recv {
                set req.backend_hint = mycluster.backend();
            }

            负载均衡算法:
                fallback, random, round_robin, hash
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值