varnish04-varnish如何使用VCL

1、VCL基础

  • Varnish Configuration Language (VCL)是一种特定于领域的语言,可以用于描述Varnish Cache服务如何处理请求和缓存策略。当加载新配置时,由Manager进程创建的VCC进程将VCL代码转换为C。该C代码通常由gcc编译为共享对象,然后将共享对象加载到缓存进程中。
  • varnish说明:http://book.varnish-software.com/4.0/chapters/VCL_Basics.html#subroutines-legal-returns-client

1.1、Varnish是有限状态机

  • VCL工作流被看作是一个有限状态机,如图所示:
    • 该图显示了Varnish有限状态机的简化版本,没有列出所有的可能转换,只是其中的一个典型集合

  • varnish中的子程序以vcl_开头,例如sub vcl_recv。
  • Return(action)终止子程序,其中action是指示下一步操作的关键字。

1、VCL有限状态机

  • (1)每个请求都单独处理。
  • (2)每个请求在任意时间都独立于其他请求。
  • (3)状态是相关的,但又是孤立的。(相关是指一个状态到另一个状态,孤立是指状态之间互不影响)
  • (4)return(action)。退出当期状态并指示请求进入到下一个状态。
  • (5)内置的VCL代码始终存在,并附加在自定义(您自己)的VCL代码下面。即内置的VCL代码是默认配置

2、VCL4.0架构原理

  • VCL有多个子程序,每个子程序之间存在相关性,但子程序又彼此间互相隔离。每个子程序可使用Return(action)指明关联至哪个下一级子程序。每个子程序对应于vcl文件中的一个配置段,即为subroutine(子程序)。
    • 例如,vcl_hash --> return(hit) --> vcl_hit

(1)前端状态可分为四个阶段

第一阶段:
vcl_recv        #接受客户端请求,对请求方法进行判断
第二阶段:
vcl_hash        #进行hash计算,不进行处理,计算之后送往各个第三阶段子程序中
第三阶段:
vcl_hit	        #缓存命中,到此处理
vcl_pass        #缓存跳过
vcl_miss        #缓存未命中
vcl_purge       #清理缓存
vcl_pipe        #对于无法识别的http请求方法直接送入管道,交由后端处理不再处理
第四阶段:
vcl_deliver     #大部分响应客户端的请求由此发送回去
vcl_synth       #接受来自vcl_purge的任务,对指定的缓存,进行删除处理

(2)后端状态分为两阶段

第一阶段:
vcl_backend_fetch       #接受来自前端状态vcl_pass或vcl_miss 的任务,向后端主机请求
第二阶段:
vcl_backend_response    #接受到后端返回正常状态报文,进行是否缓存检查,需要缓存的响应将其缓存,不需要则不缓存,最后送到vcl_deliver
vcl_backend_error       #后端主机错误,返回错误响应

(3)两个特殊的子程序

  • vcl_init:在处理任何请求之前要执行的vcl代码。主要用于初始化VMODs。
  • vcl_fini:所有的请求都已经结束,在vcl配置被丢弃时调用。主要用于清理VMODs。

1.2、VCL语法

1、VCL的基本语法

  • (1)vcl配置文件以"vcl 4.0"开头。
  • (2)使用C语言的注释风格://、#和/* foo */
  • (3)子程序使用sub关键字声明, 例如sub vcl_recv { ...}。
  • (4)不支持循环,有状态限制的变量。(变量和子程序相关,即一个变量只能用在某些子程序中)
  • (5)每一个子程序都使用return(action)结束,并指明下一个子程序,action为关键字。例如,return(pass)
  • (6)区域专用,所有的配置都只用于一个域
  • (7)引用VCL配置文件。例如,include "foo.vcl";
  • (8)加载varnish模块(VMODs)。例如,import foo;

2、VCL配置文件

  • 从Varnish 4.0开始,每个VCL文件必须以"VCL 4.0"开头(在文件顶部)。
  • 块由花括号分隔,语句以分号结束。
  • VCL中的子程序既不接受参数,也不返回值。VCL中的子程序只能通过HTTP报头交换数据。
  • VCL有终止语句,而不是传统的返回值。子程序在执行return(*action*)语句时结束执行。动作告诉Varnish下一步要做什么。例如,“在缓存中查找这个”,“不要在缓存中查找这个”,或者“生成一个错误消息”。
  • VCL有两个指令来引用另一个文件的内容。即include和import,用于不同的目的。

3、VCL中的三种语句

//声明一个子函数
sub subroutine {
  ...
}

//结束子函数,并指定下一步
return()

//判断语句
if CONDITION {
  ...
} else {	
  ...
}

1.3、VCL的内置函数、关键字和操作符

  • 内置函数:允许修改字符串、添加禁令、重新启动VCL状态引擎并将控制返回到Varnish运行时(VRT)环境。
    • regsub(str, regex, sub):以字符串str作为输入,用正则表达式regex匹配它,并用另一个字符串替换它,只更改第一个匹配项。
    • regsuball(str, regex, sub):以字符串str作为输入,用正则表达式regex匹配它,并用另一个字符串替换它,更改所有匹配项。
    • ban(boolean expression):将使缓存中与布尔表达式匹配的所有对象失效。
    • hash_data(input):指定哈希计算的数据。减少差异,以提升命中率。
    • synthetic(str)
  • 所有的函数在所有子程序中都是可用的,除了下表中列出的函数。

  • 关键字
    • call subroutine
    • return(action)
    • new
    • set
    • unset
  • 操作符
    • 比较操作符:==、!=、>、>=、<、<=
    • 逻辑操作符:&&、||、!
    • 正则匹配:~
      • (?i)表示忽略大小写
      • 字符串需要使用双引号""
    • 变量赋值:=

示例:

//obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次数;
if (obj.hits>0) {
  set resp.http.X-Cache = "HIT via " + server.ip;
} else {
  set resp.http.X-Cache = "MISS via " + server.ip;
}

1.4、子程序可以使用的动作(Action)

  • 子程序的return中可以使用的动作(Action)有:lookup、synth、purge、pass、pipe、fetch、deliver、hash、restart、retry和abandon。
  • VCL的frontend子程序可以使用的动作(Action)

  • VCL的backend子程序可以使用的动作(Action)

1.5、VCL子程序中的变量

  • 内置变量
    • req.*:request,由客户端发送到varnish的请求报文。
      • req.http.*
      • req.http.User-Agent、req.http.Referer、...
    • bereq.*:由varnish发往后端服务器的请求报文。
      • bereq.http.*
    • beresp.*:由后端服务器响应给varnish的响应报文。
      • beresp.http.*
    • resp.*:由varnish响应给客户端的响应报文
    • obj.*:存储在缓存空间中的缓存对象的属性(只读)。
  • 常用内置变量
    • bereq.*和req.*:
      • bereq.http.HEADERS:请求头
      • bereq.request:请求方法。
      • bereq.url:请求的url。
      • bereq.proto:请求的协议版本。
      • bereq.backend:指明要调用的后端主机。
      • req.http.Cookie:客户端的请求报文中Cookie的值(req专用)
      • req.http.User-Agent:浏览器类型(req专用)
    • beresp.*和resp.*:
      • beresp.http.HEADERS:响应头。
      • beresp.status:响应的状态码。
      • beresp.proto:协议版本。
      • beresp.backend.name:BE主机的主机名。
      • beresp.ttl:BE主机响应的内容的余下的可缓存时长。
    • obj.*:
      • obj.hits:此对象从缓存中命中的次数。
      • obj.ttl:对象的ttl值,缓存时长。
      • obj.grace:缓存宽限时间。
    • server.*:
      • server.ip:varnish自己的ip地址。
      • server.hostname:varnish自己的主机名。
      • server.port:varnish自己的端口。
    • client.*:
      • client.ip
      • client.hostname
      • client.port
  • 用户自定义变量
    • set
    • unset
  • VCL子程序中的变量可用性

  • 请求(req.)变量的值自动分配给后端请求(bereq.)变量。但是,这些值可能略有不同,因为Varnish可能会修改客户端请求。例如,来自客户端的HEAD请求可以转换为对后端的GET请求。
  • 后端响应(beresp.)变量的更改会影响响应(resp.)和对象(obj.)变量。obj变量赋值给resp变量,可以将obj变量发送给客户端。

2、VCL子程序

  • VCL子程序的特性:
    • 可定制的VCL子程序有:vcl_recv、vcl_pass、vcl_backend_fetch、vcl_backend_response、vcl_hash、vcl_hit、vcl_miss、vcl_deliver和vcl_synth。
    • 如果自定义VCL子程序没有return,则跳过内置VCL子程序。
    • 内置VCL子程序总是附加到自定义VCL子程序中。
  • 可以在VCL子程序中自定义Varnish的行为。
    • 例如,添加自定义报头、更改Varnish错误消息的外观、在Varnish中添加HTTP重定向功能、清除内容以及定义缓存对象的哪些部分是唯一的。
  • 注意,只要可能,强烈建议使用默认的内置子程序。内置子程序在设计时考虑到了安全性,这通常意味着它们能够以合理的方式处理VCL代码中的任何缺陷。
  • 处理客户端请求的流程图:

  • 将请求发送到后端服务器的流程图:

2.1、vcl_recv子程序

  • vcl_recv是在Varnish将客户端请求解析为其基本数据结构之后执行的第一个VCL子程序。
  • vcl_recv子程序的特性:
    • 规范化客户端输入
    • 重写的客户端数据
    • 修复错误。例如,index.htlm -> index.html
    • 根据客户端输入决定缓存策略
    • 为请求选择一个后端服务器
    • 访问控制列表(ACL)
    • 安全屏障,如SQL注入攻击
  • vcl_recv有四个主要用途:
    • 修改客户端数据以减少缓存多样性。例如,删除Host头中的“www.”。
    • 决定使用哪个web服务器。
    • 根据客户端数据确定缓存策略。例如,不缓存POST请求,但缓存特定的url。
    • 执行特定web应用程序所需的重写规则。
  • vcl_recv中的return可以使用的动作(action):
    • pass:会跳过缓存查找(lookup),但会执行Varnish后续的工作流程,且不会缓存后端服务器的响应。
      • pass适用于处理静态页面,如GET/HEAD请求等。POST请求一般用于处理动态数据,不适用pass处理策略。
    • pipe:会创建一个全双工管道,将客户端请求直接转发到后端服务器,Varnish不会检查该请求,也不会对其进行处理。后端服务器的响应也直接被转发到客户端上,且不会缓存后端服务器的响应。由于Varnish不再尝试将内容映射到请求,因此通过同一个keep-alive连接发送的任何后续请求也将通过管道传输。管道请求不会出现在任何日志中。
      • pipe不缓存数据,适用于请求类型,即通过POST类型进行文件上传、下载等操作,还适用于变更频率较大的数据,如热点数据等。
    • hash:在缓存中查找请求。
    • purge:在缓存中查找请求,以便删除其缓存。
    • synth:Varnish直接生成一个响应报文,并响应给客户端。这种响应通常是一个带有错误消息的网页。Synth也可以用来重定向客户端请求。

示例1:

  • 内置的vcl_recv
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);
}

示例2:

  • 为移动设备和桌面浏览器提供不同内容的一种方法是在User-Agent报头上运行一些简单的解析。下面的VCL代码是创建自定义标头的示例。这些自定义头将移动设备与桌面计算机区别开来。
sub vcl_recv {
    if (req.http.User-Agent ~ "iPad" ||
        req.http.User-Agent ~ "iPhone" ||
        req.http.User-Agent ~ "Android") {

        set req.http.X-Device = "mobile";
    } else {
        set req.http.X-Device = "desktop";
    }
}

示例3:

  • 重写URL和主机报头字段
sub vcl_recv {
    set req.http.x-host = req.http.host;
    set req.http.x-url = req.url;
    #删除域名中的前缀"www."
    set req.http.host = regsub(req.http.host, "^www\.", "");
    #删除域名中的前缀"sport.",并重写uri。例如http://sport.example.com/index.html --> http://example.com/sport/index.html
    if (req.http.host == "sport.example.com") {
        set req.http.host = "example.com";
        set req.url = "/sport" + req.url;
     }
    ##删除域名中的前缀"sport.",并重写uri。
    if (req.http.host ~ "^sport\.") {
        set req.http.host = regsub(req.http.host,"^sport\.", "");
        set req.url = regsub(req.url, "^", "/sport");
    }
}

2.2、vcl_pass子程序

  • vcl_pass子程序被return(pass)调用。并将请求设置为通过模式。vcl_pass通常是在vcl_hit和vcl_miss中被调用。
  • vcl_pass中的return可以使用的动作(action):fetch、synth和restart
    • fetch:将当前请求以pass模式继续。从pass模式的请求中获取的对象不会被缓存,而是传递给客户端。
    • synth和restart:调用它们相应的子程序。
  • hit-for-pass:当一个对象不应该被缓存时,应该使用Hit-for-pass对象,而不是fetch对象。hit-for-pass对象有有TTL。
    • 一些请求的对象(响应报文)不应该被缓存。一个典型的例子是当被请求的页面包含Set-Cookie响应头时,必须将它只被传递给请求它的客户端。在这种情况下,可以创建一个hit-for-pass对象并将其存储在缓存中,而不是存储所获取的对象(响应报文)。后续请求以pass模式处理。
    • 当一个对象(响应报文)不应该被缓存时,beresp.uncacheable变量被设置为true。因此,缓存进程保持对hit-for-pass对象的哈希引用。通过这种方式,转换到该散列的请求的查找操作会找到一个hit-for-pass对象。这样的请求被移交给vcl_pass子程序,并以pass模式进行。
    • 与任何其他缓存对象一样,hit-for-pass对象也有一个TTL。一旦对象的TTL结束,就会从缓存中删除。

示例:

  • 内置的vcl_pass
sub vcl_pass {
    return (fetch);
}

2.3、vcl_backend_fetch子程序

  • vcl_backend_fetch可以从vcl_miss或vcl_pass调用。
    • 如果从vcl_miss调用vcl_backend_fetch,所获取的对象(响应报文)可能会被缓存。
    • 如果从vcl_pass调用vcl_backend_fetch,即使obj.ttl或obj.keep变量大于0,所获取的对象(响应报文)也不会被缓存。
  • 一个相关的变量是bereq.uncacheable。此变量指示从后端请求的对象(响应报文)是否可以缓存。但是,不管bereq.uncacheable是什么,响应pass请求的所有对象(响应报文)都不会被缓存。
  • vcl_backend_fetch中的return可以使用的动作(action):fetch和abandon
    • fetch:将请求发送到后端,而放弃调用vcl_synth子程序。
  • 后端响应由vcl_backend_response或vcl_backend_error处理,具体取决于来自服务器的响应。如果Varnish收到一个语法正确的HTTP响应,Varnish将控制权传递给vcl_backend_response。语法正确的HTTP响应包括HTTP 5xx错误代码。如果Varnish没有收到HTTP响应,它将控制权传递给vcl_backend_error。

示例:

  • 内置的vcl_backend_fetch
sub vcl_backend_fetch {
    return (fetch);
}

2.4、vcl_hash子程序

  • vcl_hash总是在vcl_recv之后或当另一个子程序的return(hash)调用。
  • vcl_hash创建用于缓存对象的hash键。hash键可以区分不同的缓存对象。vcl_hash的默认VCL将主机名或IP地址以及请求的URL添加到缓存散列中。
  • vcl_hash中的return可以使用的动作(action):lookup
    • lookup是一种查找操作,而不是子程序。vcl_hash之后要访问哪一个子程序取决于lookup在缓存中找到的内容。
    • lookup操作的结果有四种可能:hit、miss、hit-for-pass和busy
  • 当lookup操作匹配不到任何hash键时,它会创建一个带有busy(繁忙)标志的对象,并将其插入缓存中。然后,请求被发送到vcl_miss子程序。一旦处理了请求,busy标志将被删除,对象将使用后端响应进行更新。
    • 随后遇到busy标记对象的类似请求被发送到等待列表。此等待列表旨在提高响应性能,它将解释等待状态部分。

示例:

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

2.5、vcl_hit子程序

  • lookup操作(vcl_hash中的lookup)找到请求的对象时,调用的vcl_hit子程序。
  • vcl_hit中的return通常使用的动作(action)有:deliver、restart和synth
    • deliver:如果对象的"TTL + 宽限期"还没有过去,return(deliver)会调用vcl_deliver。如果经过的时间大于TTL,但小于"TTL + 宽限时间",则将从后端服务器获取响应,然后调用vcl_deliver。(即vcl_hit{} --> BGFETCH --> vcl_deliver{})
    • Restart:重新启动事务,并增加重新启动计数器。如果重启次数高于max_restart计数器,vrnish会报出异常。
    • synth(status code, reason):返回指定的状态码给客户端,并放弃请求。

示例:

  • 内置的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);
}

2.6、vcl_miss子程序

  • lookup操作(vcl_hash中的lookup)没有找到请求的对象时,调用的vcl_miss子程序。
  • vcl_miss子程序可以用于决定是否尝试从后端检索文档,以及使用哪个后端。
  • vcl_hit和vcl_miss是密切相关。
    • 很少定制它们,因为HTTP请求头的修改通常在vcl_recv中完成。然而,如果不希望将X-Varnish头发送到后端服务器,可以在vcl_miss或vcl_pass中删除它。例如,"unset bereq.http.x-varnish;"。

示例:

  • 内置的vcl_miss
sub vcl_miss {
    return (fetch);
}

2.7、vcl_deliver子程序

  • vcl_deliver是所有请求工作流的公共最后出口点,通过vcl_pipe的请求除外。通常用于添加和删除调试用的header头(debug-headers)。
  • vcl_deliver中最有用和最常修改的变量是:
    • resp.http.*
    • resp.status
    • resp.reason:返回给客户端的HTTP状态消息。
    • obj.hits
    • req.restarts:VCL中发出的重启次数。如果没有发生则为0。

示例:

  • 内置的vcl_deliver
sub vcl_deliver {
    return (deliver);
}

2.8、vcl_synth子程序

  • varnish直接生成响应报文,并响应给客户端。
  • synth()函数必须携带状态代码和原因参数,以传递给vcl_synth。在resp.http可以设置响应报文的header头。
  • vcl_synth定义的对象永远不会存储在缓存中与vcl_backend_error定义的对象相反,vcl_backend_error定义的对象可能最终存储在缓存中。vcl_synth和vcl_backend_error替换Varnish 3中的vcl_error。

示例:

  • 内置的vcl_synth
sub vcl_synth {
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + resp.status + " " + resp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + resp.status + " " + resp.reason + {"</h1>
    <p>"} + resp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );
    return (deliver);
}

示例2:

sub vcl_recv {
    if (req.http.host == "www.example.com") {
        set req.http.location = "http://example.com" + req.url;
        return (synth(750, "Permanently moved"));
    }
}

sub vcl_synth {
    if (resp.status == 750) {
        set resp.http.location = req.http.location;
        set resp.status = 301;
        return (deliver);
    }
}

3、VCL配置示例

  • 重新加载VCL配置文件的两种方法:
//方法一,使用varnish_reload_vcl命令
]# varnish_reload_vcl

//方法二,varnishadm命令
]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.load test1 default.vcl    #重新加载vcl,并指定一个命名test1。如果返回状态码是200,则语法正确,编译通过
varnish> vcl.use test1                 #使用名为test1的VCL配置
varnish> vcl.list                      #查看所有的VCL配置,可以看到当期使用的是test1,其状态是active
200        
available       0 boot
active          0 test1

3.1、为响应报文增加一个header头

//为响应报文增加一个header头"X-cache",表示是否使用缓存(cache)。HIT是命中缓存,MISS是没有命中缓存。
sub vcl_deliver {
    if (obj.hits>0) {
        set resp.http.X-cache = "HIT via " + server.ip;
    } else {
        set resp.http.X-cache = "MISS form "+ server.ip;
    }
}

3.2、对特定资源的请求不检查缓存

//如果uri以"/login"或"/admin"开头,则不检查缓存
sub vcl_recv {
    if (req.url ~ "(?i)^/(login|admin)") {
        return(pass);
    }
}

3.3、对特定资源的请求,取消cookie

//对特定的资源的请求,取消其私有标识cookie,并设定其可以由varnish缓存的时长。例如公开的图片等。
sub vcl_backend_response {
    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;
        }
    }
}

3.4、将client的IP传给后端服务器

//将client的IP传给后端服务器,client可能是nginx调度器
sub vcl_recv {
    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;
        }
    }
}

3.5、禁止使用curl命令

sub vcl_recv {
    if (req.http.User-Agent ~ "(?i)curl") {
        return(synth(403));
    }
}

3.6、清理缓存对象

  • 清理缓存对象有两种方法:
    • purge:使用purge方法请求一个url,只要该utl被命中,该缓存就会被删除。一次清理一个url的缓存。
    • ban:可以使用正则表达式去匹配url,所有被匹配到的url的缓存都会被删。批量清理缓存。
  • varnish说明:http://book.varnish-software.com/4.0/chapters/Cache_Invalidation.html

1、purge方法

(1)创建一个能执行purge操作的子函数

sub vcl_purge {
    return(synth(200,"Purged"));
}

(2)调用vcl_purge,执行purge操作

sub vcl_recv {
    if (req.method == "PURGE") {
        return(purge);
    }
}

(3)测试

curl -I http://10.1.1.11:8080/index.html
curl -X PURGE http://10.1.1.11:8080/index.html

(4)为purge添加访问控制法则

//定义一个子函数(先定义后使用)。注意,地址要加引号,掩码在外面
acl purgers {
    "127.0.0.0"/8;
    "10.1.1.0"/16;
}
//调用purgers子函数
sub vcl_recv {
    if (req.method == "PURGE") {
        #调用acl的purgers
        if (!client.ip ~ purgers) {
            return(synth(405,"Purging not allowed for " + client.ip));
        }
        return(purge);
    }
}

2、ban方法

  • 方法一:在varnishadm命令行中使用,直接批量清理缓存,只要url被匹配到就会清理掉
ban <field> <operator> <arg> [&& <field> <oper> <arg>]...

//测试
ban req.url ~ ^/javascripts
ban req.url ~ .js$              #点不用转义
  • 方法二:在配置文件中vcl_recv定义,使用ban()函数(只能对特定资源执行ban)
//调用ban子函数
sub vcl_recv {
    if (req.method == "BAN") {
        ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
        return(synth(200, "Ban added"));
    }
}

//测试
ban req.http.host == 10.1.1.11 && req.url == /javascripts/
ban req.url == / && req.http.host ~ “ilinux.io”

curl -I http://10.1.1.11:8080/javascripts/
curl -X BAN http://10.1.1.11:8080/index.html

3.7、定义多个后端服务器

  • varnish说明:http://book.varnish-software.com/4.0/chapters/Saving_a_Request.html

1、定义多个后端服务器

#(1)导入模块
import directors;
#(2)定义后端服务器
backend hh1 {
    .host = "10.1.1.12";
    .port = "80";
}
backend hh2 {
    .host = "10.1.1.13";
    .port = "80";
}
#(3)定义后端服务器组(round_robin和random)
sub vcl_init {
    new hh_group1 = directors.round_robin();
    hh_group1.add_backend(hh1);
    hh_group1.add_backend(hh2);

    new hh_group2 = directors.random();
    hh_group2.add_backend(hh1, 10);
    hh_group2.add_backend(hh2, 5);
}
#(4)通过调用后端服务器组来调用后端服务器
sub vcl_recv {
    set req.backend_hint = hh_group1.backend();
}

2、实现动静分离

sub vcl_recv {				
    if (req.url ~ "(?i)\.php$") {
        set req.backend_hint = hh_group1.backend();;
    } else {
        set req.backend_hint = hh_group2.backend();;
    }
}

3、基于cookie实现会话粘性

sub vcl_init {
    new h = directors.hash();
    h.add_backend(hh1, 1);
    h.add_backend(hh2, 1);
}

sub vcl_recv {
    #根据客户端的cookie头选择一个后端
    set req.backend_hint = h.backend(req.http.cookie);
}

3.8、后端服务器的健康状态检测

  • varnish说明:http://book.varnish-software.com/4.0/chapters/Saving_a_Request.html

1、健康状态检测的两种配置方法

方法一:probe单独定义,在backend中调用

probe PB_NAME {
    ...
}

backend NAME {
    .probe = PB_NAME;
    ...
}

方法二:probe直接定义在backend中

backend NAME {
    .probe = {
        ...
    }
}

2、健康状态检测的基本指令

backend server1 {
    .host = "server1.example.com";
    .port = "80";
    .probe = {                   #定义健康状态检测的方式
        .url = "/healthtest";    #对uri进行健康状态检测,默认为"/"
        .timeout = 1s;           #超时时长;
        .interval = 4s;          #健康状态检测的时间间隔
        .window = 5;             #基于最近的多少次检查来判断其健康状态
        .threshold = 3;          #.window中定义的检查次数中至少有.threshold定义的次数是成功的,才认为后端服务器是可用的
    }
}
  • probe其他可用指令:
    • .request:发出的具体请求。.request和.url用其一即可。
    • .expected_response:期望的响应码,默认为200。
.request =
    "GET /.healthtest.html HTTP/1.1"
    "Host: www.hengha.com"
    "Connection: close"

3、手动设置健康状态

backend.set_health hh1 sick       #不健康
backend.set_health hh1 healthy    #健康
backend.set_health hh1 auto       #自动检测

3.9、设置后端服务器的属性

backend default {
    .host = "localhost";
    .port = "80";
    .connect_timeout = 0.5s;        #连接后端主机的超时时间
    .first_byte_timeout = 20s;      #第一个字节的超时
    .between_bytes_timeout = 5s;    #字节之间的超时
    .max_connections = 50;          #后端打开的最大连接数。达到后,varnish将连接失败。
}

1

#                                                                                                                        #
posted @ 2022-12-18 18:49  麦恒  阅读(183)  评论(0编辑  收藏  举报