一 工作原理
在当前主流的Web服务架构体系中,Cache担任着越来越重要的作用。常见的基于浏览器的C/S架构,Web Cache更是节约服务器资源的关键。而最近几年由FreeBSD创始人之一Kamp开发的varnish更是一个不可多得的Web Cache Server。严格意义上说,Varnish是一个高性能的反向代理软件,只不过与其出色的缓存功能相比,企业更愿意使用其搭建缓存服务器。同时,由于其工作在Web Server的前端,有一部分企业已经在生产环境中使用其作为旧版本的squid的替代方案,以在相同的服务器成本下提供更好的缓存效果,Varnish更是作为CDN缓存服务器的可选服务之一。
Varnish主要有以下几点特性:
1.缓存位置:可以使用内存也可以使用磁盘。如果要使用磁盘的话推荐SSD做RAID1
2.日志存储:日志也存储在内存中。存储策略:固定大小,循环使用
3.支持虚拟内存的使用。
4.有精确的时间管理机制,即缓存的时间属性控制。
5.状态引擎架构:在不同的引擎上完成对不同的缓存和代理数据进行处理。可以通过特定的配置语言设计不同的控制语句,以决定数据在不同位置以不同方式缓存。类似于netfilter中的钩子,在特定的地方对经过的报文进行特定规则的处理。
6.缓存管理:以二叉堆格式管理缓存数据,做到数据的及时清理。
二 基本架构
1. 状态引擎
2.内部处理流程
三 配置详解
1. 简单安装
[root@node1 ~]# yum install varnish -y
2. 配置详解
[root@node1 ~]# cd /etc/varnish
配置default.vcl配置文件
[root@node1 varnish]# cat default.vcl # 使用varnish版本4的格式. vcl 4.0; # 加载后端轮询模块 import directors; #######################健康检查策略区域########################### # 名为www_probe的健康检查策略 probe www_probe { .request = "GET /html/test.html HTTP/1.1" # 健康检查url为/html/test.html 协议为http1.1 # "Host: www.xiaxiaodie.com" # 访问的域名为www.xiaxiaodie.com "Connection: close"; # 检查完关闭连接 #其他参数 如 超时时间 检查间隔 等 均使用默认 } ################################################################## #######################配置后端区域################################ backend backend_15 { .host = "172.18.67.15"; .port = "80"; .probe = www_probe; # 使用名为www_probe的健康检查策略 } backend backend_16 { .host = "172.18.67.16" .port = "80"; .probe = www_probe; # 使用名为www_probe的健康检查策略 } #默认后端 backend default { .host = "172.18.67.15" .port = "80"; } ################################################################### # 配置后端集群事件 sub vcl_init { # 后端集群有4种模式 random, round-robin, fallback, hash # random 随机 # round-robin 轮询 # fallback 后备 # hash 固定后端 根据url(req.http.url) 或 用户cookie(req.http.cookie) 或 用户session(req.http.sticky)(这个还有其他要配合) # 把backend_15 和 backend_16配置为轮询集群 取名为www_round_robin new www_round_robin = directors.round_robin(); www_round_robin.add_backend(backend_15); www_round_robin.add_backend(backend_16); # 把backend_15 和 backend_16配置为随机选择集群 取名为www_random new www_random = directors.random(); www_random.add_backend(backend_15,10); # 设置backend_15后端的权重为10 www_random.add_backend(backend_16,5); # 设置backend_16后端的权重为5 # 把backend_15 和 backend_16配置为固定后端集群 取名为www_hash 在recv调用时还需要添加东西 看recv例子 new www_hash = directors.hash(); www_hash.add_backend(backend_15,1); # 设置backend_15后端的权重为1 www_hash.add_backend(backend_16,1); # 设置backend_16后端的权重为1 } #定义允许清理缓存的IP acl purge { # For now, I'll only allow purges coming from localhost "127.0.0.1"; "localhost"; } # 请求入口 这里一般用作路由处理 判断是否读取缓存 和 指定该请求使用哪个后端 sub vcl_recv { # 域名为 www.xiaxiaodie.com 的请求 指定使用名为www_round_robin的后端集群 在集群名后加上 .backend() 如只使用单独后端 直接写后端名字即可 如 = backend_16; if (req.http.host ~ "node2") { set req.backend_hint = www_round_robin.backend(); } # 使用固定后端集群例子 使用名为www_hash的集群 if (req.http.host ~ "3g.xiaxiaodie.com") { set req.backend_hint = www_hash.backend(req.http.cookie); # 根据用户的cookie来分配固定后端 可以指定其他分配规则 } # 其他将使用default默认后端 # 把真实客户端IP传递给后端服务器 后端服务器日志使用X-Forwarded-For来接收 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; } } # 匹配清理缓存的请求 if (req.method == "PURGE") { # 如果发起请求的客户端IP 不是在acl purge里面定义的 就拒绝 if (!client.ip ~ purge) { return (synth(405, "This IP is not allowed to send PURGE requests.")); } # 是的话就执行清理 return (purge); } # 如果不是正常请求 就直接穿透没商量 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") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } # 如果不是GET和HEAD就跳到pass 再确定是缓存还是穿透 if (req.method != "GET" && req.method != "HEAD") { return (pass); } # 缓存通过上面所有判断的请求 (只剩下GET和HEAD了) return (hash); } # pass事件 sub vcl_pass { # 有fetch,synth or restart 3种模式. fetch模式下 全部都不会缓存 return (fetch); } # hash事件(缓存事件) sub vcl_hash { # 根据以下特征来判断请求的唯一性 并根据此特征来缓存请求的内容 特征为&关系 # 1. 请求的url # 2. 请求的servername 如没有 就记录请求的服务器IP地址 # 3. 请求的cookie hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } # 返回lookup , lookup不是一个事件(就是 并非指跳去sub vcl_lookup) 他是一个操作 他会检查有没有缓存 如没有 就会创建缓存 return (lookup); } # 缓存命中事件 在lookup操作后自动调用 官网文档说 如没必要 一般不需要修改 sub vcl_hit { # 可以在这里添加判断事件(if) 可以返回 deliver restart synth 3个事件 # deliver 表示把缓存内容直接返回给用户 # restart 重新启动请求 不建议使用 超过重试次数会报错 # synth 返回状态码 和原因 语法:return(synth(status code,reason)) # 这里没有判断 所有缓存命中直接返回给用户 return (deliver); } # 缓存不命中事件 在lookup操作后自动调用 官网文档说 如没必要 一般不需要修改 sub vcl_miss { # 此事件中 会默认给http请求加一个 X-Varnish 的header头 提示: nginx可以根据此header来判断是否来自varnish的请求(就不用起2个端口了) # 要取消此header头 只需要在这里添加 unset bereq.http.x-varnish; 即可 # 这里所有不命中的缓存都去后端拿 没有其他操作 fetch表示从后端服务器拿取请求内容 return (fetch); } # 返回给用户的前一个事件 通常用于添加或删除header头 sub vcl_deliver { # 例子 # set resp.http.* 用来添加header头 如 set resp.http.xiaxiaodie = "haha"; unset为删除 # set resp.status 用来设置返回状态 如 set resp.status = 404; # obj.hits 会返回缓存命中次数 用于判断或赋值给header头 # req.restarts 会返回该请求经历restart事件次数 用户判断或赋值给header头 # 根据判断缓存时间来设置xiaxiaodie-Cache header头 if (obj.hits > 0) { set resp.http.xiaxiaodie_Cache = "cached"; } else { set resp.http.xiaxiaodie_Cache = "uncached"; } #取消显示php框架版本的header头 unset resp.http.X-Powered-By; #取消显示nginx版本、Via(来自varnish)等header头 为了安全 unset resp.http.Server; unset resp.http.X-Drupal-Cache; unset resp.http.Via; unset resp.http.Link; unset resp.http.X-Varnish; #显示请求经历restarts事件的次数 set resp.http.xiaxiaodie_restarts_count = req.restarts; #显示该资源缓存的时间 单位秒 set resp.http.xiaxiaodie_Age = resp.http.Age; #显示该资源命中的次数 set resp.http.xiaxiaodie_hit_count = obj.hits; #取消显示Age 为了不和CDN冲突 unset resp.http.Age; #返回给用户 return (deliver); } #处理对后端返回结果的事件(设置缓存、移除cookie信息、设置header头等) 在fetch事件后自动调用 sub vcl_backend_response { #后端返回如下错误状态码 则不缓存 if (beresp.status == 499 || beresp.status == 404 || beresp.status == 502) { set beresp.uncacheable = true; } #如请求php或jsp 则不缓存 if (bereq.url ~ ".(php|jsp)(?|$)") { set beresp.uncacheable = true; #php和jsp以外的请求 } else { #如请求html 则缓存5分钟 if (bereq.url ~ ".html(?|$)") { set beresp.ttl = 300s; unset beresp.http.Set-Cookie; #其他缓存1小时 如css js等 }else{ set beresp.ttl = 1h; unset beresp.http.Set-Cookie; } } #开启grace模式 表示当后端全挂掉后 即使缓存资源已过期(超过缓存时间) 也会把该资源返回给用户 资源最大有效时间为6小时 set beresp.grace = 6h; #返回给用户 return (deliver); }
配置varnish.params配置文件
[root@node1 varnish]# vim varnish.params # Varnish environment configuration description. This was derived from # the old style sysconfig/defaults settings # Set this to 1 to make systemd reload try to switch VCL without restart. RELOAD_VCL=1 # Main configuration file. You probably want to change it. VARNISH_VCL_CONF=/etc/varnish/default.vcl # Default address and port to bind to. Blank address means all IPv4 # and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted # quad, or an IPv6 address in brackets. # VARNISH_LISTEN_ADDRESS=192.168.1.5 VARNISH_LISTEN_PORT=80 # Admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # Shared secret file for admin interface VARNISH_SECRET_FILE=/etc/varnish/secret # Backend storage specification, see Storage Types in the varnishd(5) # man page for details. VARNISH_STORAGE="malloc,256M" # User and group for the varnishd worker processes VARNISH_USER=varnish VARNISH_GROUP=varnish # Other options, see the man page varnishd(1) #DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
3.简单管理工具
[root@node1 varnish]# varnishadm -S secret -T 127.0.0.1:6082 200 ----------------------------- Varnish Cache CLI 1.0 ----------------------------- Linux,3.10.0-327.el7.x86_64,x86_64,-smalloc,-smalloc,-hcritbit varnish-4.0.4 revision 386f712 Type 'help' for command list. Type 'quit' to close CLI session. help 200 help [<command>] ping [<timestamp>] auth <response> quit banner status start stop vcl.load <configname> <filename> vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> vcl.discard <configname> vcl.list param.show [-l] [<param>] param.set <param> <value> panic.show panic.clear storage.list vcl.show [-v] <configname> backend.list [<backend_expression>] backend.set_health <backend_expression> <state> ban <field> <operator> <arg> [&& <field> <oper> <arg>]... ban.list
四 访问测试
[root@node1 varnish]# systemctl start varnish.service