zoukankan      html  css  js  c++  java
  • varnish配置语言(2)


    知识来源为官方文档:
    《Varnish用户指南》
    《Varnish4.0稳定版参考指南》

    1. Backend servers

    Varnish有一个“后端”或“原始”服务器的概念,指真正提供内容的 web 服务器,或称为"upstream server"
    后端 web 服务器通过 Varnish 的缓存功能对访问进行加速。

    首先,告诉Varnish在哪里可以找到它的后端。编辑缓存策略配置文件"$varnish_home/default.vcl"

    在顶部的某个地方会有一个看起来像这样的部分。

    vcl 4.0;
    
    backend default {
        .host = "127.0.0.1";
        .port = "8080";
    }
    

    这里定义了一个后端服务器,名为 default。当 Varnish 需要从后端获取内容,它会连接到 127.0.0.1:8080。

    Varnish 可定义多个后端服务器,并且可以联合多个后端服务器为一个后端集群,进行负载均衡。

    2. 多个后端

    在某些情况下,您可能需要清漆来缓存来自多个服务器的内容。您可能希望Varnish将所有URL映射到一个主机上,或者不希望这样做。有很多选择。

    结合上一节配置的基础上,假设我们需要在我们的PHP网站中引入一个Java应用程序。假设我们的Java应用程序应该处理以/Java/开头的URL。我们设法让它启动并在端口8000上运行。

    backend java {
        .host = "127.0.0.1";
        .port = "8000";
    }
    

    现在我们需要告诉Varnish将差异URL发送到哪里。调用vcl_recv。

    在 vcl_recv 中,我们根据请求的 URL,给请求打上不同的 hint,使其发往指定的后端服务器。

    sub vcl_recv {
        if (req.url ~ "^/java/") {
            set req.backend_hint = java;
        } else {
            set req.backend_hint = default;
        }
    }
    

    about:variable "req"

    如果要将移动设备发出的请求,发给专门的后端服务器,可以做这样的判断:

    if (req.http.User-agent ~ /mobile/) .. 
    

    如果没有明确的后端选择,varnish将继续使用默认的后端。如果没有名为default的后端,则在vcl中找到的第一个后端将用作默认后端。

    3. Varnish 中的后端服务器和虚拟主机

    我们在 vcl_recv 中为 HTTP 请求设定路由,如果希望基于“虚拟主机”做路由,那么就对 req.http.host 变量做检查,比如:

    sub vcl_recv {
        if (req.http.host ~ "foo.com") {
            set req.backend_hint = foo;
        } elsif (req.http.host ~ "bar.com") {
            set req.backend_hint = bar;
        }
    }
    

    第一个正则表达式,能匹配 "foo.com", "www.foo.com", "zoop.foo.com",以及其他以 "foo.com" 结尾的主机名。

    也可以使用 == 进行准确的匹配:

    sub vcl_recv {
        if (req.http.host == "foo.com" || req.http.host == "www.foo.com") {
            set req.backend_hint = foo;
        }
    }
    

    4. 调度器

    我们可以将多个后端服务器组成一组,Varnish 中的组被称为 directors。将多个后端服务器组成一组可以提高性能、容错性和伸缩性。

    我们定义多个后端服务器,然后组成一个组。这要求你加载一个 VMOD:directors 模块。然后在 vcl_init 中调用一些 actions:

    import directors; # load the directors
    
    backend server1 {
        .host = "192.168.0.10";
    }
    backend server2 {
        .host = "192.168.0.11";
    }
    
    sub vcl_init {
        new bar = directors.round_robin();
        bar.add_backend(server1);
        bar.add_backend(server2);
    }
    
    sub vcl_recv {
        # send all traffic to the bar director:
        set req.backend_hint = bar.backend();
    }
    

    这个 director 是一个轮询调度器。另外还有一个随机调度器。如果一个后端服务器失效,Varnish 可以检查到,然后不再调度请求给该后端服务器。

    5. 健康检查

    我们来设置一个包含两个后端服务器的 director,并且设置健康检查,首先我们定义后端服务器:

    backend server1 {
        .host = "server1.example.com";
        .probe = {
            .url = "/";
            .timeout = 1s;
            .interval = 5s;
            .window = 5;
            .threshold = 3;
        }
    }
    
    backend server2 {
        .host = "server2.example.com";
        .probe = {
            .url = "/";
            .timeout = 1s;
            .interval = 5s;
            .window = 5;
            .threshold = 3;
        }
    }
    

    probe 引入了健康检查。此例中,Varnish 每 5 秒进行一次检查,检查超时为 1 秒。如果最近 5 次检查中,有 3+ 次成功,该后端被标记为 “healthy”,否则被标记为 “sick”。发起检查,其实是对后端服务器地址 http://host/ 发起一个 GET 请求.

    更多信息可参考Probes

    我们现在来定义 director:

    import directors;
    
    sub vcl_init {
        new vdir = directors.round_robin();
        vdir.add_backend(server1);
        vdir.add_backend(server2);
    }
    

    现在可以使用 vdir 作为 backend_hint,参考上一小节的描述,比如:

    sub vcl_recv {
        # send all traffic to the vdir director
        set req.backend_hint = vdir.backend(); 
    }
    

    Varnish 不会将流量调度给被认为不健康的后端主机。

    如果所有后端服务器失效了,Varnish还可以提供陈旧的内容。参考Grace mode and keep

    请注意,Varnish 对所有加载的 VCL 进行检查,而且会将相同的检查进行合并。所以如果你加载了很多的 VCL,注意不要修改 probe 配置。卸载 VCL 之后,检查不会继续,更多信息请求参考:ref:reference-vcl-director

    6. Hashing

    Varnish 对内容做缓存时,也要存下对应的 hash key。
    在默认的情况下,hash key 是对 Host 首部字段的值或者 IP 地址做 hash 计算,并且对 URL 做 hash 计算,得到的值,为 hash key。

    默认default.vcl:

    sub vcl_hash {
        hash_data(req.url);
        if (req.http.host) {
            hash_data(req.http.host);
        } else {
            hash_data(server.ip);
        }
        return (lookup);
    }
    

    在默认 vcl_hash 中,首先对 URL(req.url) 计算 hash 值,然后继续对 Host(req.http.host) 字段或者 IP地址计算 hash 值。

    浏览器倾向于使用小写的主机名,而Varnish在对Hostname或URL进行hash处理之前不会将其小写,因此从理论上讲,具有“ Varnish.org/”和“ varnish.org/”的Host会输入不同的缓存条目。

    这里对 hash 值的计算是逐步累加的,您可以更改hash中的内容。这样,您可以使Varnish根据任意条件为不同的客户提供不同的内容。

    比如,通过客户端的 IP 地址获知其所在的国家,基于这个提供不同的语言的网站页面(需要加载一些 VMOD 获知国家的代码),比如:

    In vcl_recv:

    set req.http.X-Country-Code = geoip.lookup(client.ip)
    

    And then add a vcl_hash:

    sub vcl_hash {
        hash_data(req.http.X-Country-Code);
    }
    

    vcl_* 系列子例程中的默认代码会在执行完我们自己编写的代码后自动执行,所以在 vcl_hash 中,默认情况下,VCL 会自动对 host 和 URL 计算 hash 值,这部分不需要我们去做。

    但要注意,不要轻易调用 return(lookup),因为它会终止默认 VCL 的执行,可能会导致 hash key 计算时,没有加入 host 和 URL。

    7. 优雅模式 Grace mode 和 keep

    有时您希望varnish为有些陈旧的内容提供服务,而不是等待来自后端的新对象。例如,您运行一个新闻站点,如果这给您的站点提供了更快的加载时间,那么为几秒钟前的主页提供服务就不是问题。
    在Varnish中,这是通过使用grace模式实现的。一个相关的想法是保持,这也解释在这里。

    7.1 宽限模式

    当几个客户端请求同一个页面的时候,varnish只发送一个请求到后端服务器,然后让那个其他几个请求挂起等待返回结果,返回结果后,复制请求的结果发送给客户端。在一些产品中,这个可能叫请求合并。varnish这些都是自动完成的。

    如果您的服务每秒有数千万的点击率,那么这个队列是庞大的。这就有两个潜在的问题:一个是惊群问题——即突然释放大量线程去复制后端的结果,可能会导致负载急剧上升。第二个问题就是没有用户喜欢等待服务器响应。为了解决这个问题,我们可以让varnish保持对象在缓存中,让它不失效,这样就可以使用缓存中内容返回给客户端,而不用担心等待。
    所以为了使用过期的 cache 给用户提供服务,我们需要增加他们的 TTL,保存所有cache 中的内容在 TTL过期以后依然可以保持2分钟

    sub vcl_backend_response {
        set beresp.grace = 2m;
    }
    

    现在Varnish允许在对象过期后2分钟内提供给客户端。同时varnish也将刷新这个对象。刷新动作是异步发生的,新的对象将替换老对象。

    你可以在vcl_hit中添加代码来影响这种逻辑的运行,默认看起来是这样的:

    sub vcl_hit {
       if (obj.ttl >= 0s) {
           // A pure unadultered hit, deliver it
           return (deliver);
       }
       if (obj.ttl + obj.grace > 0s) {
           // Object is in grace, deliver it
           // Automatically triggers a background fetch
           return (deliver);
       }
       // fetch & deliver once we get the result
       return (fetch);
    }
    

    grace逻辑在这里很明显。如果你开启了健康检查,你可以检查后端是否出了问题,然后直接宽限对象失效时间即可。用如下的if语句替换掉上面的第二个if语句块:

    if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
          return (deliver);
    } else {
          return (fetch);
    }
    

    综上所述,优雅模式解决了两个问题:

    • 提供旧内容给客户端以避免请求堆积。
    • 如果你允许varnish可以提供过期的内容。

    7.2 keep

    设置对象的keep会告诉Varnish,它应该将对象保留在缓存中一段时间。设置keep的原因是使用该对象构造条件GET后端请求(具有If-Modified-Since:和/或Ìf-None-Match:标头),从而允许后端以304 Not Modified响应进行回复,可能在后端效率更高,并节省了重新传输未更改的主体的麻烦。

    这些值是可加的,因此,如果宽限期是10秒,保持时间是1分钟,则TTL过期后,对象将在缓存中保留70秒。

    7.3 设置宽限期并保持时间

    我们可以使用VCL使Varnish在所有对象的TTL之外保持10分钟,宽限期为2分钟:

    sub vcl_backend_response {
         set beresp.grace = 2m;
         set beresp.keep = 8m;
    }
    

    7.4 宽限期和保持的效果

    对于大多数用户而言,为每个对象设置默认宽限度和/或合适的宽限度就足够了。默认的VCL将做正确的事情,并如上所述执行操作。但是,如果要自定义清漆的行为,则应了解有关其工作原理的一些详细信息。

    当结尾为(这是默认行为)时,Varnish会在其缓存中查找匹配的对象。然后,如果仅发现其TTL耗尽的对象,则Varnish将考虑以下事项:sub vcl_recvreturn (lookup)

    • 是否已经有对该对象的正在进行的后端请求?
    • 对象是否在宽限期内?

    然后,Varnish使用以下规则做出反应:

    • 如果宽限期已用完,并且没有正在进行的后端请求,那么将立即被调用,并且该对象将用作304候选对象。sub vcl_miss
    • 如果宽限期已用完,并且有一个正在进行的后端请求,则该请求将等待,直到后端请求完成。
    • 如果没有对该对象的后端请求,则会安排一个。
    • 假设对象将被交付,则立即调用。sub vcl_hit

    请注意,后端获取异步进行,新对象进入其中的那一刻将替换我们已经拥有的对象。

    如果您未定义自己的,则使用默认的。看起来像这样:sub vcl_hit

    sub vcl_hit {
         if (obj.ttl >= 0s) {
              // A pure unadulterated hit, deliver it
              return (deliver);
         }
         if (obj.ttl + obj.grace > 0s) {
              // Object is in grace, deliver it
              // Automatically triggers a background fetch
              return (deliver);
         }
         // fetch & deliver once we get the result
         return (miss);
    }
    

    内置VCL的效果实际上等同于以下内容:

    sub vcl_hit {
         return (deliver);
    }
    

    这是因为总会评估为true。但是,VCL照原样向用户展示了如何区分纯匹配和宽限匹配。在下一个主要版本的Varnish中,计划将默认VCL更改为后者的较短版本。obj.ttl + obj.grace > 0s

    7.5 不工作的后端服务器

    Varnish的一个关键特性是,它能够防止web服务器和应用服务器的错误行为。

    如果启用了健康检查,您可以检查后端是否生病,并在grace时修改行为。这可以通过以下方式实现:

    sub vcl_backend_response {
         set beresp.grace = 24h;
         // no keep - the grace should be enough for 304 candidates
    }
    
    sub vcl_recv {
         if (std.healthy(req.backend_hint)) {
              // change the behavior for healthy backends: Cap grace to 10s
              set req.grace = 10s;
         }
    }
    

    7.6 小结

    宽限模式允许Varnish向客户端交付稍微陈旧的内容,同时从后端获取新版本。结果是更快的加载时间和更低的成本。

    可以通过设置限制查找期间的宽限期req.grace,然后更改涉及宽限期的行为。通常,这样做是为了根据后端的运行状况更改有效宽限期。

    8. retry Return Action

    • 适用于vcl_backend_response和vcl_backend_error
    • 重新输入 vcl_backend_fetch
    • 所做的任何更改都将保留
    • 参数max_retries安全防范无限循环
    • 计数器bereq.retries记录了多少次重试
    sub vcl_backend_response {
        if (beresp.status == 503) {
            return (retry);
        }
    }
    

    该retry返回动作是可用的vcl_backend_response和vcl_backend_error。此操作将重新进入vcl_backend_fetch子例程。这仅影响后端线程,不影响客户端处理。

    当后端无法响应时,您可能要使用此操作。这样,Varnish可以将请求重试到另一个后端。为此,您必须定义多个后端。

    您可以使用导向器让Varnish选择下一个后端进行尝试。或者,您可以bereq.backend用来专门选择另一个后端。

    return (retry)递增bereq.retries计数器。如果重试次数大于max_retries,则控制权传递给vcl_backend_error。

    **注**:在Varnish 3.0中,在后端响应失败后可以return (restart)。这现在称为return(retry),并跳转回vcl_backend_fetch。
    

    9. Saint Mode

    Saint模式被实现为具有以下功能的后端控制器:

    • 细粒度的健康检查;维护对象与后端之间关系的黑名单
    • 对象具有黑名单TTL
    • 黑名单中的后端具有相关对象的阈值
    • 可以选择对象低于阈值的后端来服务其他对象
    • 对于所有对象,超过阈值的后端对象将被标记为所有对象的病态

    在Varnish Cache 4.1或更高版本中可用
    Saint模式通过标记特定对象的后端疾病来补充常规的“ 健康检查”。圣徒模式是一种VMOD,可维护对象和相关后端的黑名单。每个列入黑名单的对象都有一个TTL,表示它停留在黑名单中的时间。

    如果后端的黑名单对象数低于阈值,则该后端被认为部分生病。对列入黑名单的对象的请求可能会发送到另一个后端。当后端的列入黑名单的对象数超过阈值时,对于所有请求,该后端都将标记为“不正常”。

    以下vcl/saintmode.vcl是saint模式的典型用法。在此示例中,具有500响应状态的请求将重试到另一个后端。

    vcl 4.0;
    
    import saintmode;
    import directors;
    
    backend server1 { .host = "192.0.2.11"; .port = "80"; }
    backend server2 { .host = "192.0.2.12"; .port = "80"; }
    
    sub vcl_init {
            # create two saint mode backends with threshold of 5 blacklisted objects
            new sm1 = saintmode.saintmode(server1, 5);
            new sm2 = saintmode.saintmode(server2, 5);
    
            # group the backends in the same cluster
            new fb = directors.fallback();
            fb.add_backend(sm1.backend());
            fb.add_backend(sm2.backend());
    }
    
    sub vcl_backend_fetch {
            # get healthy backend from director
            set bereq.backend = fb.backend();
    }
    
    sub vcl_backend_response {
            if (beresp.status > 500) {
                    # the failing backend is blacklisted 5 seconds
                    saintmode.blacklist(5s);
                    # retry request in a different backend
                    return (retry);
            }
    }
    

    一种替代方法是使用陈旧对象构建响应。对于这一点,你会return(abandon),restart请求中vcl_synth,检查req.restarts中vcl_recv。要更好地了解操作方法,请查看https://github.com/fgsch/vcl-snippets/blob/master/v4/stale-if-error.vcl中的stale-if-error代码段。

    对圣徒模式的细粒度检查有助于发现后端发生故障的问题。例如,如果对对象foo的请求返回不带内容()的HTTP响应,则可以将该特定对象列入特定后端的黑名单。您也可以使用打印对象并将其过滤。200 OKContent-Length = 0std.logvarnishlog

    **注意**:有关更多信息,请参阅https://github.com/varnish/varnish-modules/blob/master/docs/vmod_saintmode.rst中的文档。
    

    10. 调整后端属性

    如果后端没有足够的资源,那么最好设置max_connections。因此,一个特定的后端处理有限数量的并发连接。所有后端特定的计时器都可以作为参数使用,并且可以在VCL的后端特定级别上重写。

    Tip Varnish只接受解析为最多一个IPv4地址和一个IPv6地址的后端服务器的主机名。参数prefer_ipv6定义Varnish更喜欢哪个IP地址。

    backend default {
        .host = "localhost";
        .port = "80";
        .connect_timeout = 0.5s;
        .first_byte_timeout = 20s;
        .between_bytes_timeout = 5s;
        .max_connections = 50;
    }
    

    11. 使用 inline C to 扩展 Varnish

    (Here there be dragons. Big and mean ones.),不建议使用,有兴趣参考官方《 inline C扩展varnish》

    #include语句必须在子例程之外。
    C { 
            #include <syslog.h> 
    } C
    
    sub vcl_something { 
            C { 
                    syslog (LOG_INFO , “在VCL线XX上发生了什么。” ); 
            } C 
    }
    

    VCL示例及其他内容,请自行参照《Varnish4.1官方文档》


     
    [sleepy↓]

     

  • 相关阅读:
    响应式布局设计的三大要点
    一个前端的自我修养(转载)
    JavaScript利用闭包实现模块化
    关于清除浮动的几种方法
    支持向量机(SVM)
    拉格朗日对偶问题与 KKT 条件
    朴素贝叶斯模型
    快速傅里叶变换(FFT)
    用线性代数理解 Normal Equation
    用线性代数解释图论中的一些结论
  • 原文地址:https://www.cnblogs.com/sunhongleibibi/p/11732982.html
Copyright © 2011-2022 走看看