Varnish 配置与管理

管理varnish以及清除内存等操作虽然可以使用varnishadm,但是这里推荐使用telnet,一个交互的管理界面。

比如: telnet 127.0.0.1 6082

之后,输入help会显示所有可用命令。

help [command] ping [timestamp] status
start
stop
stats
vcl.load
vcl.inline
vcl.use
vcl.discard
vcl.list
vcl.show
param.show [-l] [] param.set
quit
purge.url
purge.hash
purge    [&&   ]...
purge.list

重新加载Varnish配置文件

telnet 127.0.0.1 6082 vcl.load newconfig /data/app/varnish/etc/varnish/default.vcl
vcl.use newconfig

注意:varnish 的CLI可能需要认证,最简单的办法就是在varnish启动的时候取掉相应的参数。

-S /etc/varnish/secret \

参考 https://www.varnish-cache.org/docs/trunk/reference/varnish-cli.html

Varnish的缓存方式

Malloc (malloc) 通过 malloc 获取内存,简单,速度快

Mmap file (file) 创建文件缓存

这个是varnish缓存的两种方式,可以在启动的时候通过参数指定。

Varnish处理流程

首次请求时过程如下:

recv->hash->miss->fetch->deliver

缓存后再次请求:

recv->hash->hit->deliver(fetch的过程没了,这就是我们要做的,把要缓存的页面保存下来)

直接交给后端pass的情况:

recv->hash->pass->fetch->deliver(直接从后端获取数据后发送给客户端,此时Varnish相当于一个中转站,只负责转发)

VCL以及基本对象

request 从客户端进来

responses 从后端服务器过来

object 存储在cache中

VCL语言

req 请求目标,当varnish接收到一个请求,这时req object就被创建了,你在vcl_recv中的大部分工作,都是在req object上展开的。

beresp 后端服务器返回的目标,它包含返回的头信息,你在vcl_fetch中的大部分工作都是在beresp object上开展的。

obj 被cache的目标,只读的目标被保存于内存中,obj.ttl的值可修改,其他的只能读。

VCL支持一下运算符

= 赋值运算符

== 对比

~ 匹配,在ACL中和正则表达式中都可以用

! 否定

&& 逻辑与

|| 逻辑或

Grace mode

如果后端需要很长时间来生成一个对象,这里有一个线程堆积的风险。为了避免这 种情况,你可以使用 Grace。他可以让 varnish 提供一个存在的版本,然后从后端生成新 的目标版本。

当同时有多个请求过来的时候,varnish只发送一个请求到后端服务器,在“set beresp.grace = 30m; ”时间内复制旧的请求结果给客户端。

Saint mode

有时候,服务器很古怪,他们发出随机错误,您需要通知 varnish 使用更加优雅的方式处理 它,这种方式叫神圣模式(saint mode)。Saint mode 允许您抛弃一个后端服务器或者另一 个尝试的后端服务器或者 cache 中服务陈旧的内容。

sub vcl_fetch {  if (beresp.status == 500) {   set beresp.saintmode = 10s;
  restart;
 }  set beresp.grace = 5m;}

Varnish代理

########
backend default {
  .host = "192.168.0.12";
  .port = "8080";
}
#现在添加一个新的backend服务器
backend test {
  .host = "192.168.0.12";
  .port = "8000";
}
#要定义特殊的url被发送到哪里sub vcl_recv {
  if (req.url ~ "^/abcd/") {
    set req.backend = test;
  } else {
    set req.backend = default;
  }
}

Varnish负载均衡

可以把多台 backends 聚合成一个组,这些组被叫做directors。这样可以增强性能和弹力。您可以定义多个backends和多个group在同一个directors。

backend server1 {
    .host = "192.168.0.1" ;
    .port = "8080" ;
}
backend server2 {
    .host = "192.168.0.2" ;
    .port = "8080" ;
}
director drupal001 round-robin {
    { .backend = server1; }
    { .backend = server2; }
}sub vcl_recv {
   if (req.http.host !~ "www\.drupal001\.com$"){
      error 404 "Unknown HostName!";
    }
    set req.backend = drupal001;
 }

健康检查

在之前的两个后端服务器上加上健康检查。

backend server1 {
    .host = "192.168.0.1" ;
    .port = "8000" ;
    .probe = {
      .url = "/";       #哪个 url需要varnish请求。
      .interval = 5s;   #检查的间隔时间。
      .timeout = 1 s;   #等待多长时间探针超时。
      .window = 5;      #维持5个sliding window的结果。
      .threshold = 3;   #至少有三次window是成功的,就宣告bachend健康。
     }
}

主备

后端备份。在recv里增加了
if (req.restarts == 0) {
    set req.backend = backend1;
} else  {
    set req.backend = backend2;
}
在fetch里增加了
if (beresp.status != 200 && req.restarts == 0) {
    restart;
}
或在error里加restart

重点参考https://www.varnish-cache.org/docs/3.0/reference/vcl.html

注意事项:

1. Varnish的不同版本的配置不同,必须查阅官方文档。

比如,在2.x 直接用ESI表示启用ESI,在3.x就不是了。

2. Varnish 2.x有Cookie的问题,当Cookie过大,会产生503错误,升级varnish或者减少set_cookie的操作。

3. 启动varnishd的时候如果选用-s file方式,每次会重新建立缓存文件,而原来的文件不会删除,因此注意清除这些遗留文件。

注释完整的一段VCL文件参考

 

#设置后端服务器地址
backend default {
     .host = "127.0.0.1";
     .port = "80";
}
 
#允许刷新缓存的ip
acl purgeAllow {
     "localhost";
     "192.168.56.1";
}
 
sub vcl_recv {
     #刷新缓存设置
     if (req.request == "PURGE") {
          #判断是否允许ip
          if (!client.ip ~ purgeAllow) {
               error 405 "Not allowed.";
          }
          #去缓存中查找
          return (lookup);
     }
 
     #首次访问增加X-Forwarded-For头信息,方便后端程序
     #获取客户端ip
     if (req.restarts == 0) {
          #如果设置过此header则要再次附加上,用,隔开,如果
          #只有一层代理的话,就无需设置了
          if (req.http.x-forwarded-for) {
               set req.http.X-Forwarded-For =
                    req.http.X-Forwarded-For ", " client.ip;
          }
          #没有则要加上
          else {
               set req.http.X-Forwarded-For = client.ip;
          }
     }
 
     #修正客户端的Accept-Encoding头信息,默认选用gzip方式
     #防止个别浏览器发送类似 deflate, gzip
     #当然后端如果只支持gzip的话.可以只设置gizp
     if (req.http.Accept-Encoding) {
          if (req.http.Accept-Encoding ~ "gzip") {
               set req.http.Accept-Encoding = "gzip";
          }
          #如果后端支持deflate方式,建议去掉,否则刷新缓存时
          #需特殊处理
          elsif (req.http.Accept-Encoding ~ "deflate") {
               set req.http.Accept-Encoding = "deflate";
          }
          #其他的压缩方式忽略
          else {
               remove req.http.Accept-Encoding;
          }
     }
 
     #静态文件和明确以.php结尾的url无需缓存, 建议把静态文件分离
     #至单独服务器下,减少动态应用服务器压力,同时降低arnishd的压力
     if(req.url ~ "\.(png|gif|jpg|css|js|php)$"){
          return (pass);
     }
 
     #非正规的请求直接转发给后端服务器
     if (req.request != "GET" &&
          req.request != "HEAD" &&
          req.request != "PUT" &&
          req.request != "POST" &&
          req.request != "TRACE" &&
          req.request != "OPTIONS" &&
          req.request != "DELETE") {
          /* Non-RFC2616 or CONNECT which is weird. */
          return (pipe);
     }
 
     #只处理GET和HEAD请求,如果你不想缓存POST的页面话
     if (req.request != "GET" && req.request != "HEAD") {
          return (pass);
     }
     #http认证的页面也pass
     if (req.http.Authorization) {
          return (pass);
     }
 
     return (lookup);
}
 
#管道?按官方文档说的是此模式下请求会原封不动的转交给后端知道连接关闭
sub vcl_pipe {
     return (pipe);
}
 
#交给后端服务器
sub vcl_pass {
    return (pass);
}
 
#缓存文件名的哈希处理
sub vcl_hash {
     #以url为hash
     set req.hash += req.url;
     #加上host
     if (req.http.host) {
          set req.hash += req.http.host;
     }
     #没有则取ip
     else {
          set req.hash += server.ip;
     }
     #支持压缩的要增加,防止发送给不支持压缩的浏览器压缩的内容
     if(req.http.Accept-Encoding){
          set req.hash += req.http.Accept-Encoding;
     }
     return (hash);
}
 
#缓存命中后的处理
sub vcl_hit {
     #如果不可缓存,直接交给后端
     if (!obj.cacheable) {
          return (pass);
     }
     #如果为更新缓存的请求,则设置ttl为0,并告知客户端处理结果
     if (req.request == "PURGE") {
          set obj.ttl = 0s;
          error 200 "Purged.";
     }
 
     set resp.http.X-Cache = "HIT“
     return (deliver);
}
 
#缓存未命中
sub vcl_miss {
     #更新缓存的请求,提示缓存不存在Not in cache
     if (req.request == "PURGE") {
          error 404 "Not in cache.";
     }
     #既然缓存不存在了,就去后端取吧
     return (fetch);
}
#
sub vcl_fetch {
 
     #是否开启ESI功能(仅做演示用,单独给/esi-test.html开启esi)
     if (req.url == "/esi-test.html") {
          esi;
     }
 
     #如果后端返回不可缓存,直接pass
     if (!beresp.cacheable) {
          return (pass);
     }
 
     #/article/下的url缓存30分钟(演示用)
     if (req.url ~ "^/article/\d+\.html$"){
          set beresp.ttl = 30m;
     }
 
     #/category/下的url缓存20分钟(演示用)
     if (req.url ~ "^/category/$"){
          set beresp.ttl = 20m;
     }
 
     #如果后端发送了set-cookie头信息(如session会话开启),则不缓存
     if (beresp.http.Set-Cookie) {
          return (pass);
     }
 
     return (deliver);
}
 
#发送给客户端
sub vcl_deliver {
     #去掉varnish中的一些头信息(如果你不想保留的话,建议保留Age,方便查看)
     #remove resp.http.X-Varnish;
     #remove resp.http.Via;
     return (deliver);
}
 
#定义错误页面的信息
sub vcl_error {
     #设置返回页面的类型及编码
     set obj.http.Content-Type = "text/html; charset=utf-8";
     #具体内容,可以更加自己的需要修改错误提示信息
     synthetic {"
       HTTP ERROR
    "};
     return (deliver);
}

官方文档

非常重要,必须参考。

https://www.varnish-cache.org/docs

官方示例 Example

https://www.varnish-cache.org/trac/wiki/VCLExamples

VCL2.x升级到3.0

https://www.varnish-cache.org/docs/3.0/installation/upgrade.html 

WIKI

https://www.varnish-cache.org/trac/ 

drupal on Varnish

https://www.varnish-cache.org/trac/wiki/VarnishAndDrupal 

 

 

 

http://www.drupal001.com/2011/12/varnish-drupal-basic/

此条目发表在web server分类目录,贴了标签。将固定链接加入收藏夹。