一、Varnish概述
2.1.1 Varnish的结构与特点
 Varnish是一个轻量级别的Cache和反向代理软件,先进的设计理念和成熟的设计框架是Varnish的主要特点:
	基于内存进行缓存,重启后数据将消失
	利用虚拟内存方式,I/O性能好.
	支持设置0~60秒的精确缓存时间
	VCL配置管理比较灵活
	32位机器上缓存文件大小为最大2GB
	具有强大的管理功能,例如:top stat admin list等
	状态设计巧妙,结构清晰
	利用二叉堆管理缓存文件,达到可以积极***目的。

2.1.2 Varnish与Squid的对比
  说到Varnish,就不能不提Squid,Squid是一个高性能的代理缓存服务器,它和Varnish的相比较有诸多的异同点,下面进行分析:
        相同点:
	都是一个反向代理服务器
	都是开源软件
     
        异同点,也是Varnish的优点:
	Varnish的稳定性很高,两者在完成相同的负荷的工作时,Squid发生的故障几率要高于Varnish,因为Squid需经常重启.
	Varnish访问速度更快,Varnish采用用了”Visual Page Cache”技术,所有缓存的数据都直接从内存读取,而且Squid是从硬盘读取缓存数据,因此Varnish访问速度更快
	Varnish可以支持更多的并发连接,因为Varnish的TCP连接要比Squid释放快,所以在高并发连接情况可以支持更多地TCP连接。
	Varnish可以通过管理端口,使用正则表达式清除部分缓存,而Squid做不到。
     Varnish缺点如下:
	在高并发状态下CPU,I/O和内存等资源开销都要高于Squid。
	Varnish进程一旦挂起,崩溃或者重启,缓存数据都会从内存当中完全释放,此时所有的请求会发送后端的WEB服务器,在高并发的情况下,这会给后端的服务器造成很大压力。

  Internet外网
      |
  ---FW-->防火墙
      |
      |
      |
      |
--Varnish1  --Varnish2  --Varnish3
   |            |            |
   |            |            |
   |            |            |
   |            |            | 
 WEB1          WEB2         WEB3

二、Varnish安装
2.1、环境:
Varnish-server:10.0.0.202
Nginx-Server:10.0.0.201

2.2.2、创建Varnish用户缓存目录和日志
# useradd varnish -s /sbin/nologin   创建varnish用户
# mkdir /varnish/cache –p         创建varnish缓存目录
# mkdir /varnish/log              创建varnish日志 
# chown -R varnish:varnish /varnish/  修改赋权组


2.2.3、安装PCRE 
为了兼容正则表达式,编译 2.0以上版本时否则会报错pcre找不到。
# yum install gcc 
# yum install gcc-c++ libstdc++-devel
# yum install -y httpd-devel pcre perl pcre-devel zlib zlib-devel GeoIP GeoIP-devel
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.34.tar.bz2
# tar -xvf pcre-8.34.tar.bz2
# cd pcre-8.34/
# ./configure --prefix=/usr/local/prce/
# make && make install

2.2.4、安装Varnish
# wget http://repo.varnish-cache.org/source/varnish-3.0.0.tar.gz
# tar -xzvf varnish-3.0.0.tar.gz
# cd varnish-3.0.0
#./configure --prefix=/usr/local/varnish PKG_CONFIG_PATH=/usr/lib/pkgconfig
# make && make install
# cd /usr/local/varnish/sbin
./varnishd -V


2.3.1、VCL使用说明
VCL,即Varnish Configaution Language 用来定义Varnish的存储策略
VCL内置函数
   (1)、vcl_recv函数
用于接收和处理请求,当请求到达并成功接收后被调用.
    函数一般以如下几个关键字结束
pass表示进入pass模式,把请求控制权交给vcl_pass函数
pige 表示进入pige模式,把请求控制权交给vcl_pipe函数
error code[reason] 表示返回”code”给客户,并放弃处理该请求,”code”是错误的标识
,例如:200和405等,”reason”是错误信息

(2)、vcl_pipe函数
   此函数在进入pipe模式时被调用,用于请求直接传至后端主机,在请求和返回内容没有改变的情况下,将不变的内容返回给客户端,直到这个连接被关闭。
   此函数一般以如下几个关键字结束:
     error code[reason]
     pipe
(3)、vcl_pass函数
   此函数在进入pass模式时被调用,用于请求直接传至后端主机,后端主机但应数据,将答应的数据传至客户端,但不进行任何缓存,当前连接下每次都返回最新的内容。
此函数一般以如下几个关键字结束:
error code[reason]
     pass

(4)、lookup函数
   表示在缓存中查找被请求的对象,并且根据查找的结果把控制权交给vcl_hit或者函数vcl_miss

(5)、vcl_hit函数
在执行lookup指令后,在缓存中找到请求的内容后将自动调用该函数
此函数一般以如下几个关键字结束:
fetch 表示从后端获取请求的内容,并且把控制权交给vcl_fetch函数
  deliver  表示将找到的内容发送给客户,并且把控制权交给函数vcl_deliver
error code[reason]
pass

(6)、vcl_miss函数
   在执行lookup指令后,在缓存中没有找到请求的内容时自动调用该方法,此函数可以于判断是否需要从后端服务器获取内容
  此函数一般以如下几个关键字结束:
fetch:表示从后端获取请求内容,并且把控制权交给vcl_fetch函数
error code[reason]
pass

(7)、vcl_miss函数
在后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端,
   此函数一般以如下几个关键字结束:
 error code[reason]
pass
deliver 

(8)、vcl_deliver函数
  将在缓存中找到请求的内容发送给客户端调用此方法。
此函数一般以如下几个关键字结束:
error code[reason]
deliver 

(9)、vcl_timeout函数
 在缓存内容到期前调用此函数.
此函数一般以如下几个关键字结束:
 discard:表示从缓存中清除内容
 fetch

(10)、vcl_discard函数
  在缓存内容到期后或者缓存空间不足时,自动调用该函数.
此函数一般以如下几个关键字结束:
  keep:表示将内容继续保留在缓存当中
discard 


三、Varnish配置
2.3.2、配置Varnish配置实战
由于本版不同,Varnish配置文件的写法也存在一定的差异,Varnish3.x版本不但在配置写法上和2.x版本不同,修复了很多不应用BUG,本文以3.x版本为基准
   Varnish安装完成后,默认的配置文件/usr/local/varnish/etc/varnish/default.vcl
 此配置文件默认是全部注释掉的.配置文件如下:
先编辑配置文件
# vi /usr/local/varnish/etc/varnish/default.vcl
# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
# 
# Default backend definition.  Set this to point to your content
# server.
# 

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
#设置后端WEB服务-关注点
backend webtest1 {
    .host = "10.0.0.201";
    .port = "80";
    .connect_timeout = 1s;
    .first_byte_timeout = 5s;
    .between_bytes_timeout = 2s;
}

#可以定义多台WEB-关注点
#backend webtest2 {
#    .host = "192.168.100.6";
#    .port = "80";
#    .connect_timeout = 1s;
#    .first_byte_timeout = 5s;
#    .between_bytes_timeout = 2s;
#}
#多台WEB可以定义负载均衡-关注点lb_test,
#director lb_test random {
#    {
#      .backend = webtest1;
#      .weight = 5;
    # }
    # {
    #   .backend = webtest2;
    #   .weight = 5;
    # }
#}
#定义那些IP或者IP段具有访问权-关注点
acl purge {
    "localhost";
    "127.0.0.1";
    "192.168.1.0"/24;
    "10.0.0.0"/16;
}


sub vcl_recv {
#开启压缩模式,图片格式取消压缩
if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|jpeg|flv)" ) {
        remove req.http.Accept-Encoding;
        remove req.http.Cookie;
    } else if (req.http.Accept-Encoding ~ "gzip") {
        set req.http.Accept-Encoding = "gzip";
    } else if (req.http.Accept-Encoding ~ "deflate") {
        set req.http.Accept-Encoding = "deflate";
    } else {
        remove req.http.Accept-Encoding;
    }
}
#根据host设置后端服务器-关注点
  if (req.http.Host ~ "(?i)(www.test1.com|www.test2.com|10.0.0.202)") {
     #set req.backend = lb_test; #如果开启负载用此项,上面的负载均衡的POOL的名叫注意:lb_test
     set req.backend = webtest1;
       }else
  if (req.http.Host ~ "(?i)p_w_picpath.wdj.com"){
     set req.backend = webtest1;
  }else
  {
    error 408 "Hostname not found";
  }
#如果为purge请求,客户端ip不在访问列表中,返回405拒绝-关注点 
  if (req.request == "PURGE") {
     if (!client.ip ~purge) {
       error 405 "Not Allowed";
   }
#本地缓存查找
   return(lookup);
  }
#如果为GET请求,url后缀为jpg,png,gif等 取出cookie
  if (req.request == "GET"&&req.url ~ "(?i)\.(jpg|png|gif|swf|jpeg|ico)$") {
        unset req.http.cookie;
  }
#如果GET请求,url为php,则穿过cache,不缓存
  if (req.request =="GET"&&req.url ~ "(?i)\.php($|\?)"){
        return (pass);
  }
#简单防盗链--关注点
if (req.http.referer ~ "http://.*") {
  if ( !(req.http.referer ~ "http://.*test1\.com"
     || req.http.referer ~ "http://.*test2\.com"
     || req.http.referer ~ "http://.*wdj\.com"
     || req.http.referer ~ "http://.*google\.com"
     || req.http.referer ~ "http://.*baidu\.com"
     || req.http.referer ~ "http://.*yahoo\.cn"
  )) {
      error 404 "Not Found!";
 }
}
#获取客户端ip
#     if (req.restarts == 0) {
        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;
        }
#   }
#不是以下请求进入pipe模块
    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请求不缓存
    if (req.request != "GET" && req.request != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    if (req.http.Authorization) {
        /* Not cacheable by default */
        return (pass);
    }
    return (lookup);
}
#
 sub vcl_pipe {
     return (pipe);
 }
#
sub vcl_pass {
    return (pass);
}
#使用url+host hash算法查找数据
sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    return (hash);
}
# 如果请求为purge 将清除缓存
sub vcl_hit {
   if (req.request == "PURGE") {
       set obj.ttl = 0s;
       error 200 "Purged";
    }
    return (deliver);
}

sub vcl_miss {
    return (fetch);
}
#
sub vcl_fetch {
    if (beresp.ttl <= 0s ||
        beresp.http.Set-Cookie ||
        beresp.http.Vary == "*") {
                /*
                 * Mark as "Hit-For-Pass" for the next 2 minutes
                 */
                set beresp.ttl = 0 s;
                return (hit_for_pass);
    }
    if (beresp.http.Pragma ~"no-cache" ||
    beresp.http.Cache-Control ~"no-cache" ||
    beresp.http.Cache-Control ~"private") {
      return (deliver);
   }
#为特定格式文件设置缓存时间,有多种格式可以直接在后面加-关注点
    if (req.request == "GET"&&req.url ~ "(?i)\.(js|css|mp3|jpg|png|gif|swf|jpeg|ico)$") {
    set beresp.ttl = 30d;
  }
   if (req.request == "GET"&&req.url ~ "(?i)\.(html|htm)$") {
    set beresp.ttl = 1d;
  }
    return (deliver);
}
# 设置返回状态
 sub vcl_deliver {
     set resp.http.x-hits = obj.hits;
     if (obj.hits > 0) {
      set resp.http.X-Cache = "Hit test.com";
   }else {
       set resp.http.X-Cache = "Miss test.com";
   }
     set resp.http.Server = "BWM";
     return (deliver);
 }
# 定义错误
sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    set obj.http.Retry-After = "5";
    synthetic {"
<?xml version="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>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};
    return (deliver);
}

sub vcl_init {
        return (ok);
}

sub vcl_fini {
        return (ok);
}

四、Varnish运行
-u 以什么用运行
-g 以什么组运行
-f varnish配置文件
-a 绑定IP和端口
-s varnish缓存文件位置与大小
-w 最小,最大线程和超时时间
-t 缓存时间s
-T varnish管理端口,主要用来清除缓存
-p client_http11=on 支持http1.1协议
-P(大P) /usr/local/varnish/var/varnish.pid 指定其进程码文件的位置,实现管理
停止varnish

/usr/local/varnish/sbin/varnishd -u varnish -g varnish -f /usr/local/varnish/etc/varnish/default.vcl -a 10.0.0.202:80 -s file,/varnish/cache/varnish_cache.data,1G -w 1024,51200,10 -t 3600 -T 10.0.0.202:3000                  
企业里里面开启为100G

2.4.2、启动日志
# /usr/local/varnish/bin/varnishncsa -w  /varnish/log/varnish.log &

日志加入开机启动:
 echo "/usr/local/varnish/bin/varnishncsa -w /data/varnish/logs/varnish.log &" >> /etc/rc.local
参数: -w 指定varnish访问日志要写入的目录与文件