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.*:存储在缓存空间中的缓存对象的属性(只读)。
- req.*:request,由客户端发送到varnish的请求报文。
- 常用内置变量:
- 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
- bereq.*和req.*:
- 用户自定义变量:
- 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也可以用来重定向客户端请求。
- pass:会跳过缓存查找(lookup),但会执行Varnish后续的工作流程,且不会缓存后端服务器的响应。
示例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
# #