os:
php
[root@aliyun_test html]# cat /etc/system-releasehtml
CentOS release 6.5 (Final)java
首先安装varnish:
linux
配置好varnish源nginx
[root@aliyun_test yum.repos.d]# cat >> varnish.repo << EOFweb
> [varnish]算法
> name=varnish for enterprise linux 6vim
> baseurl=https://repo.varnish-cache.org/redhat/varnish-4.0/el6/后端
> enabled=1浏览器
> gpgcheck=0
> cost=500
> EOF
安装varnish
yum -y install varnish
[root@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
Varnish 处理 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存储缓存内容的方法:
一、file:自管理的文件系统,黑盒,只对当前进程有效,不支持持久机制;
二、malloc:使用内存分配函数malloc()库调用varnish启动时向内存申请指定大小的空间;
三、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。
}
以下结果:
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); ----》请求的是默认后端主机,若是不先设置主机将会网页访问不存在
}
}
设置默认后端效果图:
若是不先设置默认主机,效果以下:
不正常的请求不缓存 -----》在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子程序
能够看见响应报文没有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;
}
}