Varnish Cache是一个web应用程序加速器,也是一个HTTP反向代理软件。放在HTTP服务器前端,

缓存内容。采用“Visual Page Cache"技术,所有缓存数据直接从内存读取,因此速度非常快。

VCL4相比VCL3语法的改变点

  • 要在配置文件中指定版本:即在第一行写上 vcl 4.0;

  • vcl_fetch函数被vcl_backend_response代替,且req.*不再适用vcl_backend_response;

  • 后端源服务器组director成为varnish模块,需import directors后再在vcl_init子例程中定义;

  • vcl_error变更为vcl_backend_error,必须使用beresp.*,而不是obj.*。

  • req.request变更为req.method,obj为只读对象了。

  • 自定义的子例程(即一个sub)不能以vcl_开头,调用使用call sub_name;

  • error()函数被synth()替代;

  • return(lookup)被return(hash)替代;

  • 使用beresp.uncacheable创建hit_for_pss对象;

  • 变量req.backend.healty被std.healthy(req.backend)替代;

  • 变量req.backend被req.backend_hint替代;

  • 关键字remove被unset替代;

  • 关键字"purge;"命令,已被去除。在vcl_recv使用return(purge)。

  • vcl_synth采用resp.*,而非原来的obj.* 。

更详细改变,请查看官方文档。

https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.html


VCL内置函数

vcl_recv 在一个请求到达时调用,它的决定是否处理此请求,以及如何处理。可使用以下几个终止语句:

  • synth(状态码,原因)

  • pass:绕过缓存,不从缓存中查询内容也不讲内容存至缓存中

  • pipe:不对客户端进行检查或做出任何操作,通过管道直接送往后方服务器,将数据直接通过管道在两者间传送

  • purge 清除此对象

  • hash 在缓存中查找用户请求的对象,如果缓存中没有其请求的对象,后续操作很可能会将其请求的对象进行缓存;

vcl_pipe 此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,并将后端响应原样返回客户端;

  • synth(satus code,reason)

  • pipe

vcl_pass 此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,但后端主机的响应并不缓存直接返回客户端;

  • synth(status code,reason)

  • fetch 表示从后端获取请求的内容,并把控制权交给vcl_fetch函数。

  • restart 重启整个VCL,并增加重启计数;超出max_restarts限定的最大重启次数后将会返回错误信息;

vcl_hit 在执行 lookup 指令后,在缓存中找到请求的内容后将自动调用该函数;

  • restart

  • deliver 缓存此对象,并将其发送给客户端(经由vcl_deliver);

  • synth(status code,reason)

vcl_miss 在执行 lookup 指令后,在缓存中没有找到请求的内容时自动调用该方法,此函数可用于判断是否需要从后端服务器获取内容;

  • synth(status code,reason)

  • pass

  • fetch

  • restart

vcl_hash 在vcl_recv调用后为请求创建一个hash值时,调用此函数;此hash值将作为varnish中搜索缓存对象的key;

  • lookup 在缓存中查找用户请求的对象,并把控制权交给vcl_miss,vcl_hit或者vcl_purge

vcl_purge pruge操作执行后调用此函数,可用于构建一个响应;

  • synth

  • restart

vcl_deliver 将在缓存中找到请求的内容发送给客户端前调用此方法;

  • deliver

  • restart

vcl_backend_fetch 向后端主机发送请求前,调用此函数,可修改发往后端的请求;

  • fetch

  • abandon 放弃后端的请求,并生成一个错误

vcl_backend_response 获得后端主机的响应后,可调用此函数;

  • deliver

  • abandon

  • retry

vcl_backend_error 当从后端主机获取源文件失败时,调用此函数;

  • deliver

  • retry

vcl_synth

  • deliver

  • restart

vcl_init VCL加载时调用此函数,经常用于初始化varnish模块(VMODs)

  • ok 正常返回,VCL继续工作

vcl_fini 当所有请求都离开当前VCL,且当前VCL被弃用时,调用此函数,经常用于清理varnish模块;

  • ok

变量类型:

Varnish4配置详解_varnish4

  • req:The request object,请求到达时可用的变量

  • bereq:The backend request object,向后端主机请求时可用的变量

  • beresp:The backend response object,从后端主机获取内容时可用的变量

  • resp:The HTTP response object,对客户端响应时可用的变量

  • obj:存储在内存中时对象属性相关的可用的变量




案例分析:

vcl 4.0;

probe backend_healthcheck {   #健康状况监测
        .url = "/health.html";
        .timeout   = 1s;
        .interval  = 10s;
        .window    = 5;
        .threshold = 2;
}
backend web2 {   #创建后端主机
    .host = "192.168.1.139";
    .port = "80";
    .probe = backend_healthcheck;
}

backend p_w_picpath1 {
    .host = "192.168.1.140";
    .port = "80";
    .probe = backend_healthcheck;
}
backend p_w_picpath2 {
    .host = "192.168.1.141";
    .port = "80";
    .probe = backend_healthcheck;
}
backend web1 {
    .host = "192.168.1.138";
    .port = "80";
    .probe = backend_healthcheck;
}

import directors;
sub vcl_init {  #创建后端主机组,基于round_robin轮转
    new web_cluster = directors.round_robin();
    web_cluster.add_backend(web1);
    web_cluster.add_backend(web2);
    
    new img_cluster = directors.round_robin();
    img_cluster.add_backend(p_w_picpath1);
    img_cluster.add_backend(p_w_picpath2);
}

acl purgers {  #定义PURGE方法访问来源IP
	"localhost";
	"127.0.0.1";
	"192.168.1.0"/24;
}

sub vcl_recv {
    if (req.method == "GET" && req.http.Cookie) {  #缓存带cookie的GET请求
	return(hash);
    }
    if (req.url ~ "test.html") {  #测试页面不缓存
	return(pass);
    }
    if (req.method == "PURGE") { #当发送PURGE请求的客户端不再acl中指定地址时,返回405状态代码,并提示Not allowed.
	if (!client.ip ~ purgers) {
	    return(synth(405,"Not allowed"));
	}
	return(hash);
    }
    if (req.http.X-Forward-For) { #为后端主机添加X-Forward-For首部
	set req.http.X-Forward-For = req.http.X-Forward-For + "," +client.ip;
    } else {
	set req.http.X-Forward-For = client.ip;
    }
    if (req.http.host ~ "^(www.|bbs.)?mingxiao.info") {  #域名访问策略
	set req.backend_hint = web_cluster.backend();
    }
    if (req.http.host ~ "^(img.|p_w_picpaths.)?mingxiao.info") {
	set req.backend_hint = img_cluster.backend();
    }
    return(hash);	
}

sub vcl_hit { #如果请求的是PURGE方法,命中的话返回200状态码。
    if (req.method == "PURGE") {
	return(synth(200,"Purged"));
    }
}

sub vcl_miss {
    if (req.method == "PURGE") {
	return(synth(404,"Not in cache"));
    }
}

sub vcl_pass {
    if (req.method == "PURGE") {
	return(synth(502,"PURGE on a passed object"));
    }
}

sub vcl_backend_response {
    if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") {
	set beresp.ttl = 6000s;
    }
    if (bereq.url ~ "\.(html|css|js)$") {
	set beresp.ttl = 6000s;
    }
    if (beresp.http.Set-Cookie) {
	return(deliver);
    }
}
sub vcl_deliver { 
        if (obj.hits >0) {
                set resp.http.X-Cache="Hit from"+" "+server.ip;
        }
        else {
                set resp.http.X-Cache="Miss from"+" "+server.ip;
        }
}