varnish介绍
Varnish Cache是一个web应用程序加速器,也是一个HTTP反向代理软件。放在HTTP或NGINX服务器前端,缓存内容。
一、varnish软件包中的关键程序:
1.varnishd
2.varnishadmin
varnishd:
varnishd是主程序,启动后生成两个进程,Manager Process(父进程)和Cacher Process(子进程),前者在启动时读入配置文件(稍后会讲到)并fork()出后者,同时具有CLI接口接收管理员的指令以用于管理后者,后者是真正处理缓存业务的进程,其下又可以生成若干线程,这些线程各司其职,完成缓存业务的处理并记录日志。这里的Manager进程和Cacher进程类似于Nginx的Master和Worker
varnishadm:
varnishadm可以用来建立一个CLI来连接varnishd,使用-n名称或者-T和-S参数。如果提供了-n参数,密钥文件和address:port会在共享内存中被查找。如果没有提供的话,那么varnishadm将会查找一个实例而不需要指定一个名字。如果给出一个命令,命令和参数会通过CLI连接发送出去,并且结果会返回给stdout。如果没有命令参数提供,varnishadm会通过cli socket和stdin/stdout来传递命令和输出。
-n ident
通过这个名字连接varnishd-S secretfile
指定认证的密钥文件。这个需要和提供给varnishd的-S参数一致。只有它可以读取该文件的内容,并验证这个CLI连接。-t timeout
操作的超时时间。-T
连接指定地址和端口的管理接口
二、varnish配置文件
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.* 。
三、VCL内置state engine
----------------------------------------------------------------------------------------------------------------------------------
sub vcl_recv {
if (req.httpd.User-Agent ~ "iPad"
req.httpd.User-Agent ~ "iPhone"
req.httpd.User-Agent ~ "Android") {
set req.http.X-Device = "mobile";
} else {
set req.http.X-Device = "desktop";
}
}
sub vcl_recv {
set req.http.host = regsub(req.http.host,"^www\.","");
}
sub vcl_recv {
if (req.http.host == "sport.web1.com") {
set req.http.host = "web1.com";
set req.url = "/sport" + req.url;
}
}
sub vcl_recv {
if (req.http.host ~ "^sport\.") {
set req.http.host = regsub(req.http.host,"^sport\.","");
set req.url = regsub(req.url,"^","/sport");
}
}
sub vcl_backend_fetch {
return (fetch);
}
sub vcl_hash {
hash_date(req.url);
if (req.http.host) {
hash_data(req.http.host);
}
else {
hash_data(server.ip);
}
return (lookup);
}
sub vcl_hit {
if (obj.ttl >= 0s) {
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
return (deliver);
}
return (fetch);
}
sub vcl_miss {
return (fetch);
}
sub vcl_deliver {
return (deliver);
}
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);
}
default.vcl:
probe backend_healthcheck { #健康状况监测
.url = "/test1.html";
.timeout = 1s;
.interval = 10s;
.window = 5;
.threshold = 2;
}
backend web1 { #创建后端主机
.host = "192.168.50.138";
.port = "80";
.probe = backend_healthcheck;
}
backend web2 {
.host = "192.168.50.139";
.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);
}
acl purgers { #定义PURGE方法访问来源IP
"localhost";
"127.0.0.1";
"192.168.50.0"/24;
}
sub vcl_recv {
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;
}
set req.backend_hint = web_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;
}
}