实现负载均衡
varnish所支持的调度方式有以下几种:
1.round-robin #加权轮询,因为每个backend都有它的权重
2.random #随机
3.dns #基于DNS名称解析之后进行调度
例:
定义多个backend
directorNAME scheduler {
.retries = 2;
{
.backend = b1;
.weight = 2;
}
.backend = b2;
{
.backend = {
.host =
.port =
.probe =
}
.weight = 3;
}
}
其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,挑选方式为“轮叫”,并在某后端主机故障时不再将其视作挑选对象;random方法随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数以指定其权重,同时还可以director级别使用.retires参数来设定查找一个健康后端主机时的尝试次数。
Varnish 2.1.0后,random挑选方法又多了两种变化形式client和hash。client类型的director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机,client.identity默认改为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。
类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。(类似于haproxy的URI算法)
另外还有一种称作fallback的director,用于定义备用服务器,如下所示:
director b3fallback {
{ .backend = www1; }
{ .backend = www2; } // will only be used if www1 is unhealthy.
{ .backend = www3; } // will only be used if both www1 and www2
// are unhealthy.
}
作用为多级备选,如果www1在线,其他不在线了,那么所有请求都转发至www1
如果www1也不在线了直接转向www2 以此类推,所以跟负载均衡是两码事,仅是其中一个,只有其中一个不在线则使用第二个,由此我们期望之前的几台服务器被当做一组服务器来使用
而且使用随机或者轮询的方法来实现
编辑配置文件
[[email protected]]# cat test.vcl
#设置缓存机制规则
probe healtchk {
.url = "/";
.interval = 1s;
.timeout = 0.1s;
.expected_response = 200;
}
backendimg_server1 {
.host="10.0.10.63";
.port="8080";
.probe = healtchk;
}
backendapp_server1 {
.host="10.0.10.62";
.port="8080";
.probe = healtchk;
}
#使用hash调度算法,将同一来源请求都分发至同一后端服务器
directorwebservers hash{
{
.backend = img_server1;
.weight = 2;
}
{
.backend = app_server1;
.weight = 1;
}
}
#定义需要缓存内容文件
sub vcl_recv {
set req.http.X-Forward-For = client.ip;
if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {
return(pass);
}
#调用backend结果
set req.backend = webservers;
}
sub vcl_deliver {
set req.http.X-Forward-For = client.ip;
if (obj.hits > 0) {
set resp.http.X-Cache = "HITfrom"+" "+ server.ip;
} else {
set resp.http.XCahche ="MISS";
}
}
访问测试
实现varnish自动清理缓存
有两种方式可以实现自动清理缓存:
·使用pruge
修剪缓存,能够让用户清理所指定的某个特定缓存对象,如果要移除多个缓存对象,对缓存某些内容基于正则方式进行清理的话,可以进行banning这种机制
·Banning
通常可以移除指定的缓存对象或者进行匹配某些对象进行处理
想要使用purge,必须使用http协议的的purge方法即可完成,但是要注意的是其仅能用于vcl.hit和vcl.miss中,并且会释放内存而且移除缓存对象的所有变种,只要与缓存对象相关,都会被清除
如果能手动对象,而缓存的性能主要取决于缓存对象的,所以不能随意清理,因此如下所示:
#定义了acl,注意的是引号内不能有掩码位
示例
#定义了acl,注意的是引号内不能有掩码位
acl purgers {
“127.0.0.1”;
“192.168.0.0”/24;
}
sub vcl_recv {
if (req.request == “PURGE”) {
if (!client.ip ~ purgers) {
error 405 “Method not allowed”;
}
return (lookup);
}
}
#对用户请求的操作进行purge操作
#并且执行错误码,结果是200,意味着是正常响应并告知请求方被执行
#但是用户purge一个对象,但是这个对象在缓存中压根没有,那么就没必要去清理,所以定义了miss
sub vcl_hit {
if (req.request == “PURGE”) {
purge;
error 200 “Purged”;
}
}
#如果是miss的话,直接返回404,但是purge操作会正常进行
sub vcl_miss {
if (req.request == “PURGE”) {
purge;
error 404 “Not in cache”;
}
}
#
sub vcl_pass {
if (req.request == “PURGE”) {
error 502 “PURGE on a passed object”;
}
}
大致意思为:
如果用户的请求方法是purge 而且来源地址是属于允许执行purge的客户端那么则允许查询缓存
而刚好命中则删除;如果没有则告诉用户 404
修改参数如下所示:
[[email protected] varnish]# cattest.vcl
acl purgers {
"127.0.0.1";
"10.0.10.0"/24;
}
probe healtchk {
.url = "/";
.interval = 1s;
.timeout = 0.1s;
.expected_response = 200;
}
backend img_server1 {
.host = "10.0.10.63";
.port = "8080";
.probe = healtchk;
}
backend app_server1 {
.host = "10.0.10.62";
.port = "8080";
.probe = healtchk;
}
director webservers random {
{
.backend = img_server1;
.weight = 2;
}
{
.backend = app_server1;
.weight = 1;
}
}
sub vcl_recv {
if (req.request == "PURGE") {
if (!client.ip ~ purgers) {
error 405 "Methodnot allowed";
}
return (lookup);
}
set req.http.X-Forward-For = client.ip;
if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {
return(lookup);
}
set req.backend = webservers;
}
sub vcl_hit {
if(req.request == "PURGE") {
purge;
error 200 "Purged.";
}
}
sub vcl_miss {
if(req.request == "PURGE") {
purge;
error 404 "Not in cache";
}
}
sub vcl_pass {
if(req.request == "PURGE") {
error 502 "purge on a passedoject.";
}
}
sub vcl_deliver {
if(obj.hits > 0) {
set resp.http.X-Cache = "HITfrom"+" "+ server.ip;
} else {
set resp.http.XCahche ="MISS";
}
}
varnish> vcl.load test8./test.vcl
200
VCL compiled.
varnish> vcl.use test8
200
访问测试,并观察其返回头部信息
首先清除缓存信息
[[email protected] html]# curl -XPURGE http://10.0.10.61/1.html
<?xmlversion="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>200 Purged.</title>
</head>
<body>
<h1>Error 200 Purged.</h1>
<p>Purged.</p>
<h3>Guru Meditation:</h3>
<p>XID: 1620937044</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
再次请求
[[email protected] html]# curl -IPURGE http://10.0.10.61/1.html
curl: (6) Couldn‘t resolvehost ‘PURGE‘
HTTP/1.1 200 OK
Server: nginx/1.4.2
Content-Type: text/html
Last-Modified: Fri, 18 Jul2014 06:50:23 GMT
ETag: "53c8c3af-4"
Content-Length: 4
Accept-Ranges: bytes
Date: Fri, 25 Jul 201407:27:23 GMT
X-Varnish: 1620937045
Age: 0
Via: 1.1 varnish
Connection: keep-alive
XCahche: MISS
再次测试
[[email protected] html]# curl -IPURGE http://10.0.10.61/1.html
curl: (6) Couldn‘t resolvehost ‘PURGE‘
HTTP/1.1 200 OK
Server: nginx/1.4.2
Content-Type: text/html
Last-Modified: Fri, 18 Jul2014 06:50:23 GMT
ETag: "53c8c3af-4"
Content-Length: 4
Accept-Ranges: bytes
Date: Fri, 25 Jul 201407:28:29 GMT
X-Varnish: 16209370471620937045
Age: 66
Via: 1.1 varnish
Connection: keep-alive
X-Cache: HIT from 10.0.10.61
发起对某一url的请求,第一次请求一定是MISS而之后都是命中的
-X表示将缓存清除,缓存清理之后再次请求则为miss
Varnish防盗链的设置
对其使用referer变量来标注用户的来源的首部信息
一般来讲,我们的连接都应该是我们自己本身的站内连接,或者其他子站连接
因此要阻止他人盗链我们站点连接,只能判断连接来源,请求首部信息的referer是否我们允许的连接
还是需要使用if语句判断用户的连接来源是处于哪里,而后对连接本身做一些访问控制,如下所示:
例:
如果匹配http协议,就对其做判断
如果请求方的referer如果不是这个站点,则拒绝
#还需要对搜索引擎网站开放,因为搜索引擎会收录我们的站点,从而去搜索某个关键字的时候从而可以将我们的某些站点搜索出来,这样可以提高我们的点击率,所以要允许搜索引擎访问我们的站点,不然搜索引擎无法收录我们的站点
if (req.http.referer ~"http://.*"){
if(!(req.http.referer ~ "http://.*\.test\.com" ||req.http.referer ~ "http://.*\.baidu\.com\.*" )) {
setreq.http.host = "www.test.com"; #将用户请求的主机名称改为自定义名
setreq.url = "/antireferer/logo.html"; #并且直接返回我们本地资源的自定义url
}
}
只要来源不是引用以上两个站点的,则返回logo.jpg盗链图片连接
修改配置文件:
将以上参数加入至RECV中
[[email protected] varnish]# cat test.vcl
acl purgers {
"127.0.0.1";
"10.0.10.0"/24;
}
probe healtchk {
.url = "/";
.interval = 1s;
.timeout = 0.1s;
.expected_response = 200;
}
backend img_server1 {
.host = "10.0.10.63";
.port = "8080";
.probe = healtchk;
}
backend app_server1 {
.host = "10.0.10.62";
.port = "8080";
.probe = healtchk;
}
director webservers random {
{
.backend = img_server1;
.weight = 2;
}
{
.backend = app_server1;
.weight = 1;
}
}
sub vcl_recv {
#加入以下参数
if (req.http.referer ~ "http://.*"){
if(!(req.http.referer ~ "http://.*\.test\.com" ||req.http.referer ~ "http://.*\.baidu\.com\.*" )) {
set req.http.host = "www.test.com";
set req.url = "/antireferer/logo.jpg";
}
}
if (req.request == "PURGE") {
if (!client.ip ~ purgers) {
error 405 "Method notallowed";
}
return (lookup);
}
set req.http.X-Forward-For = client.ip;
if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {
return(lookup);
}
set req.backend = webservers;
}
sub vcl_hit {
if(req.request == "PURGE") {
purge;
error 200 "Purged.";
}
}
sub vcl_miss {
if(req.request == "PURGE") {
purge;
error 404 "Not in cache";
}
}
sub vcl_pass {
if(req.request == "PURGE") {
error 502 "purge on a passedoject.";
}
}
sub vcl_deliver {
if(obj.hits > 0) {
set resp.http.X-Cache = "HITfrom"+" "+ server.ip;
} else {
set resp.http.XCahche ="MISS";
}
}
[[email protected] varnish]# !ca
cat test.vcl
acl purgers {
"127.0.0.1";
"10.0.10.0"/24;
}
probe healtchk {
.url = "/";
.interval = 1s;
.timeout = 0.1s;
.expected_response = 200;
}
backend img_server1 {
.host = "10.0.10.63";
.port = "8080";
.probe = healtchk;
}
backend app_server1 {
.host = "10.0.10.62";
.port = "8080";
.probe = healtchk;
}
director webservers random {
{
.backend = img_server1;
.weight = 2;
}
{
.backend = app_server1;
.weight = 1;
}
}
sub vcl_recv {
if (req.http.referer ~"http://.*"){
if(!(req.http.referer ~"http://.*\.test\.com" || req.http.referer ~"http://.*\.baidu\.com\.*" )) {
set req.http.host ="www.test.com";
set req.url ="/antireferer/logo.jpg";
}
}
if (req.request == "PURGE") {
if (!client.ip ~ purgers) {
error 405 "Method notallowed";
}
return (lookup);
}
set req.http.X-Forward-For = client.ip;
if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {
return(lookup);
}
set req.backend = webservers;
}
sub vcl_hit {
if(req.request == "PURGE") {
purge;
error 200 "Purged.";
}
}
sub vcl_miss {
if(req.request == "PURGE") {
purge;
error 404 "Not in cache";
}
}
sub vcl_pass {
if(req.request == "PURGE") {
error 502 "purge on a passedoject.";
}
}
sub vcl_deliver {
if(obj.hits > 0) {
set resp.http.X-Cache = "HITfrom"+" "+ server.ip;
} else {
set resp.http.XCahche ="MISS";
}
}
varnish> vcl.load test10./test.vcl
200
VCL compiled.
varnish> vcl.use test10
200
建立antireferer目录
[[email protected] www]# mkdirantireferer
[[email protected] antireferer]# pwd
/var/www/html/antireferer
#上传图片
[[email protected] antireferer]# rz
[[email protected] antireferer]# ll
total 44
-rw-r--r--. 1 root root 42142May 22 2011 log.jpg
验证效果
[[email protected] antireferer]#curl -e http://www.baidu.com/a.htmlhttp://10.0.10.61/index.html
node1
11
[[email protected] antireferer]#curl -e http://www.qq.com/a.htmlhttp://10.0.10.61/index.html
<html>
<head><title>404Not Found</title></head>
<bodybgcolor="white">
<center><h1>404 NotFound</h1></center>
<hr><center>nginx/1.4.2</center>
</body>
</html>
可以看到效果,我们以baidu.com为首部对其进行请求,可访问,但如果是从qq.com对其进行资源访问则返回错误
但是为啥返回404还在研究
vcl配置基本原则
自定义vcl的时候,尽量不要拿空白文件直接写,而要复制默认配置文件,将默认配置文件的参数全部启用,再在其基础做修改,因为默认配置文件的规则比较严谨,在安全防范上有一定效果的,自己写的难免会有漏洞
所以应该以default.vcl为模板,启用其所有配置后,再进行修改
END,感谢各位。
Varnish常用配置详解