设为首页 收藏本站
查看: 662|回复: 0

[经验分享] varnish构建高速缓存

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-8-22 09:44:06 | 显示全部楼层 |阅读模式
os:

[iyunv@aliyun_test html]# cat /etc/system-release
CentOS release 6.5 (Final)
首先安装varnish:

配置好varnish源
[iyunv@aliyun_test yum.repos.d]# cat >> varnish.repo << EOF
> [varnish]
> name=varnish for enterprise linux 6
> baseurl=https://repo.varnish-cache.org/redhat/varnish-4.0/el6/
> enabled=1
> gpgcheck=0
> cost=500
> EOF
安装varnish
yum -y install varnish
[iyunv@aliyun_test html]# varnishd -V
varnishd (varnish-4.0.3 revision b8c4a34)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2014 Varnish Software AS

Built in subroutinesVarnish 处理 HTTP 请求的过程如下
Receive 状态(vcl_recv):也就是请求处理的入口状态,根据 VCL 规则判断该请求应该 pass(vcl_pass)或是 pipe(vcl_pipe),还是进入 lookup(本地查询);
Lookup 状态:进入该状态后,会在 hash 表中查找数据,若找到,则进入 hit(vcl_hit)状态,否则进入 miss(vcl_miss)状态;
Pass(vcl_pass)状态:在此状态下,会直接进入后端请求,即进入 fetch(vcl_fetch)状态;
Fetch(vcl_backend_fetch)状态:在 fetch 状态下,对请求进行后端获取,发送请求,获得数据,并根据设置进行本地存储;
Deliver(vcl_deliver)状态:将获取到的数据发给客户端,然后完成本次请求;
注:Varnish4中在vcl_fetch部分略有出入,已独立为vcl_backend_fetch和vcl_backend_response 2个函数;
内置函数(也叫子例程)
vcl_recv:用于接收和处理请求;当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求;
vcl_pipe:此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,并将后端响应原样返回客户端;
vcl_pass:此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,但后端主机的响应并不缓存直接返回客户端;
vcl_hit:在执行 lookup 指令后,在缓存中找到请求的内容后将自动调用该函数;
vcl_miss:在执行 lookup 指令后,在缓存中没有找到请求的内容时自动调用该方法,此函数可用于判断是否需要从后端服务器获取内容;
vcl_hash:在vcl_recv调用后为请求创建一个hash值时,调用此函数;此hash值将作为varnish中搜索缓存对象的key;
vcl_purge:pruge操作执行后调用此函数,可用于构建一个响应;
vcl_deliver:将在缓存中找到请求的内容发送给客户端前调用此方法;
vcl_backend_fetch:向后端主机发送请求前,调用此函数,可修改发往后端的请求;
vcl_backend_response:获得后端主机的响应后,可调用此函数;
vcl_backend_error:当从后端主机获取源文件失败时,调用此函数;
vcl_init:VCL加载时调用此函数,经常用于初始化varnish模块(VMODs)
vcl_fini:当所有请求都离开当前VCL,且当前VCL被弃用时,调用此函数,经常用于清理varnish模块;
vcl_pass:请求后端,但不进入到cache中

client---------->varnish-------------->backend severs
client------>varnish:req请求报文
varnish----->backend:bereq向后端请求
backend----->varnish:beresp后端响应给缓存服务器
varnish----->client:resp缓存响应给client
缓存处理的具体步骤:
    接受客户端请求
    解析请求(具有代理的功能)
    查询缓存(检测本地缓存中是否存在对方请求的内容的副本)
    副本的新鲜度检测(检查本地的缓存副本是否为最新版本)
    构建响应(代理的功能)
    发送响应
    记录日志

首部:
  通用首部
    Connection:close|keep-alive
    Date:日期时间
    host:请求的主机
    Pragma:no-cache
    Via:请求或响应在客户端和服务器之间传递时所经过的代理
    Transfer-Encoding:消息主体的传输编码方式,chunked表示采用块编码的方式
  请求首部
    if-modified-since
    if-none-match
    Referer:跳转
    User-Agent:用户的浏览器类型
    Host:请求的主机
    Accept-Encoding:接受的编码方式
    Accept-Language:接受的自然语言
    Authorization:服务器发送www-authenticate时,客户端通过此首部提供认证信息
    Accept-Charset:接受的字符集
  响应首部
    ETag:内容的扩展标签
    Location:重定向后的新位置
    Server:服务器软件信息
    www-authenticate:要求对客户端进行认证
  实体首部
    Content-Encoding:内容编码
    Content-Language:内容语言
    Content-Length:内容长度
    Content-Type:内容的MIME格式
    Expires:内容的过期时间
    Last-Modified:最后一次修改的时间

配置文件:
vi /etc/sysconfig/varnish
NFILES=131072:打开的最大文件数
NFILES=131072:默认日志内存大小
NPROCS="unlimited":最大线程数(ulimit -u)
RELOAD_VCL=1:直接加载,不用重启
VARNISH_LISTEN_PORT=6081:varnish服务监听的端口,一般改为与后端web服务一样的端口
VARNISH_ADMIN_LISTEN_PORT=6082:远程管理接口监听的端口
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:远程管理端监听的ip(本机varnish服务)
VARNISH_SECRET_FILE=/etc/varnish/secret:对管理接口秘钥文件
VARNISH_MIN_THREADS=50:varnish服务开启的最小线程
VARNISH_MAX_THREADS=1000:varnish服务开启的最大线程
VARNISH_STORAGE_SIZE=256M:varnish服务存储的内存大小
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}":varnish缓存存储的方式,malloc内存
VARNISH_TTL=120
vi /etc/varnish/default.vcl
backend default {:后端web服务器以及名称
    .host = "127.0.0.1";:后端web服务器主机
    .port = "8080";:后端web服务器监听的端口
}
varnish存储缓存内容的方法:      
    1、file:自管理的文件系统,黑盒,只对当前进程有效,不支持持久机制;
    2、malloc:使用内存分配函数malloc()库调用varnish启动时向内存申请指定大小的空间;
    3、persisent:与file功能相同;仍处于测试期,基于文件的持久存储。

开始配置varnish并启动:
后端服务器:120.26.68.152端口为8080,为nginx
varnish服务器:120.26.68.152端口为7480
echo "<h1> test </h1>" > /usr/share/nginx/html/index.html
配置:vim /etc/varnish/test.vcl
    设置响应是否命中
    sub vcl_deliver {                   ##定义子例程
        if (obj.hits > 0) {      
            set resp.http.X-Cache = "HIT via" + " " + server.ip;
        } else {
            set resp.http.X-Cache = "MISS via" + " " + server.ip;
        }             ##判断如果命中就在http响应首部设置X-Cache为HIT,否则
                就在http响应首部设置X-Cache为MISS。
    }
如下结果:
wKiom1e4Z-Gzki_lAAA2qTSNIHM744.jpg
Age:表示缓存的时长(这里设置一个小时),当超过这个时长之后,请求报文会再次miss,之后的1个小时才是hit
sub vcl_backend_response {
  set beresp.ttl = 1h;
}
vcl_backend_response:子程序为后端响应给varnish

一些动态解析的程序文件都不能够缓存:

backend default {     ----》先定义后端服务器
    .host = "192.168.1.112";
    .port = "80";
}
sub vcl_recv {
    set req.backend_hint = default;     ---》设置使用的backend为default
    unset req.http.Cookie;     -----》不设置客户端请求的cookie信息
    if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)$") {   ----》匹配的是默认后端主机
      return(pass);     ----》请求的是默认后端主机,如果不先设置主机将会网页访问不存在
    }
}
设置默认后端效果图:
wKioL1e5prPx0HhwAAEmfiV4IGk716.jpg
如果不先设置默认主机,效果如下:
QQ截图20160822094350.jpg

不正常的请求不缓存   -----》在vcl_rcv子程序中
   if (req.method != "GET" &&
       req.method != "HEAD" &&
       req.method != "PUT" &&
       req.method != "POST" &&
       req.method != "TRACE" &&
       req.method != "OPTIONS" &&
       req.method != "PATCH" &&
       req.method != "DELETE") {
       return (pipe);
    }

如果请求不是GET或者HEAD,不缓存
   if (req.method != "GET" && req.method !="HEAD") {
       return (pass);
    }

如果请求包含Authorization授权或Cookie认证,不缓存
   if (req.http.Authorization || req.http.Cookie) {
       return (pass);
    }

启用压缩,但排除一些流文件压缩
   if (req.http.Accept-Encoding) {
           unset req.http.Accept-Encoding;
       } elseif (req.http.Accept-Encoding ~ "gzip") {
           set req.http.Accept-Encoding = "gzip";
       } elseif (req.http.Accept-Encoding ~ "deflate") {
           set req.http.Accept-Encoding = "deflate";
       } else {
           unset req.http.Accept-Encoding;
       }
    }
       return (hash);
}

定义vcl_pipe函数段
sub vcl_pipe {
   return (pipe);
}
sub vcl_miss {
   return (fetch);
}

定义vcl_hash函数段
sub vcl_hash {
   hash_data(req.url);
   if (req.http.host) {      -----》如果请求host首部,利用has算法返回host首部信息
       hash_data(req.http.host);
    }else {
       hash_data(server.ip);
    }
   if (req.http.Accept-Encoding ~ "gzip") {
       hash_data ("gzip");
    }elseif (req.http.Accept-Encoding ~ "deflate") {
       hash_data ("deflate");
    }
}

sub vcl_recv {
    if (req.restarts ==0) {:刚接收到请求,或者再一次请求时,记录客户端首部及ip
       if (req.http.x-forwad-for) {
  set req.http.X-Forward-For = set req.http.X-Forward-For + " " client.ip;
       } else {
  set req.http.X-Forward-For = client.ip;
       }
    }
}
这里我已经改用虚拟机测试了
varnish:192.168.1.155
nginx:192.168.1.11
隐藏后端Server系统及版本
if (resp.http.Server) {
  unset resp.http.Server;
}属于sub vcl_deliver子程序
wKiom1e4eEugI16KAAA2KeGdMzk812.jpg
可以看见响应报文没有Server段了

定义两个后端:
backend default {
    .host = "192.168.1.11";
    .port = "80";
}

backend java {
    .host = "192.168.1.12";
    .port = "80";
}
当匹配java时,选择java后端,其他默认选择默认端

sub vcl_recv {
    if (req.url ~ "^/java/") {
        set req.backend_hint = java;-----》hint暗示、示意
    } else {
        set req.backend_hint = default;
    }
}
根据请求报文的主机来判断:

sub vcl_recv {
    if (req.http.host ~ "foo.com") {
        set req.backend_hint = foo;
    } elsif (req.http.host ~ "bar.com") {
        set req.backend_hint = bar;
    }
}
sub vcl_recv {

    if (req.http.host == "foo.com" || req.http.host == "www.foo.com") {
        set req.backend_hint = foo;
    }
}

定义后端组,并且采用round robin算法和后端服务器监控检测机制
import directors;    # load the directors
backend web1 {
  .host = "192.168.1.11";
  .port = "80";
  .probe = {
    .url = "/";
    .interval = 5s;
    .window = 5;
    .timeout = 1s;
    .threshold = 3;
  }
}

backend web2 {
  .host = "192.168.1.12";
  .port = "80";
  .probe = {
    .url = "/";
    .interval = 5s;
    .timeout = 1s;
    .window = 5;
    .threshold = 3;
  }
}

sub vcl_init {
  new nginx = directors.round_robin();  -----》nginx就是后端组的组名称,进行轮训
  nginx.add_backend(web1);
  nginx.add_backend(web2);
}
sub vcl_recv {
    # send all traffic to the bar director:
    set req.backend_hint = nginx.backend();
}

ACL控制列表
# Who is allowed to purge....
acl local {
    "localhost";
    "192.168.1.0"/24; /* and everyone on the local network */
    ! "192.168.1.13"; /* except for the dialin router */
}

sub vcl_recv {
  if (req.method == "PURGE") {
    if (client.ip ~ local) {
       return(purge);
    } else {
       return(synth(403, "Access denied."));
    }
  }
}
不设置请求报文的cookie信息
sub vcl_recv {
  unset req.http.Cookie;
}

不设置响应报文的cookie信息
sub vcl_backend_response {
   if (bereq.url ~ "\.(png|gif|jpg)$") {
     unset beresp.http.set-cookie;
     set beresp.ttl = 1h;
  }
}
更多信息参考:https://www.varnish-cache.org/docs/4.0


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-261203-1-1.html 上篇帖子: Ubunut14.04开启root ssh远程登录权限 下篇帖子: SSH(Spring+Struts2+Hibernate)整合
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表