varnish详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了varnish详解相关的知识,希望对你有一定的参考价值。
开源解决方案:
squid:
varnish:默认端口:6081、127.20.0.1:6082
varnish官方站点: http://www.varnish-cache.org/
Community
Enterprise
This is Varnish Cache, a high-performance HTTP accelerator.
程序架构:
Manager进程
Cacher进程,包含多种类型的线程:
accept, worker, expiry, ...
shared memory log:
统计数据:计数器;
日志区域:日志记录;
varnishlog, varnishncsa, varnishstat...
配置接口:VCL
Varnish Configuration Language,
vcl complier --> c complier --> shared object
varnish的程序环境:
/etc/varnish/varnish.params: 配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
Unit File: EnvironmentFile=""
/etc/varnish/default.vcl:配置各Child/Cache线程的缓存策略;
VCL: dsl, subroutines, 子例程
主程序:
/usr/sbin/varnishd
CLI interface:
/usr/bin/varnishadm
Shared Memory Log交互工具:
/usr/bin/varnishhist
/usr/bin/varnishlog
/usr/bin/varnishncsa
/usr/bin/varnishstat
/usr/bin/varnishtop
测试工具程序:
/usr/bin/varnishtest
VCL配置文件重载程序:
/usr/sbin/varnish_reload_vcl
Systemd Unit File:
/usr/lib/systemd/system/varnish.service
varnish服务
/usr/lib/systemd/system/varnishlog.service
/usr/lib/systemd/system/varnishncsa.service
日志持久的服务;
实例:将varnish服务设置内容http服务
126.180:httpd服务
yum -y install httpd
vim /var/www/html/index.html
not 1
systemctl start httpd.service
102.70:varnish服务器
yum -y install varnish
vim /etc/varnish/default.vcl
# Default backend definition. Set this to point to your content server.
//默认端定义。将其设置为指向内容服务器
backend default {
.host = "172.20.126.180";
//内容服务器的ip
.port = "80";
//定义的端口
启用:
systemctl start varnish
重新加载服务直接运行即可:
varnish_reload_vcl
测试:172.20.102.70:6081将显示内容跳转到126.180的httpd服务上;
varnish的缓存存储机制( Storage Types):
-s [name=]type[,options]
· malloc[,size]
内存存储,[,size]用于定义空间大小;重启后所有缓存项失效;
· file[,path[,size[,granularity]]]
磁盘文件存储,黑盒;重启后所有缓存项失效;
· persistent,path,size
文件存储,黑盒;重启后所有缓存项有效;实验;
varnish程序的选项:
程序选项:/etc/varnish/varnish.params文件
-a address[:port][,address[:port][...],默认为6081端口;
-T address[:port],默认为6082端口;
-s [name=]type[,options],定义缓存存储机制;
-u user
-g group
-f config:VCL配置文件;
-F:运行于前台;
...
运行时参数:/etc/varnish/varnish.params文件, DEAMON_OPTS
DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
-p param=value:设定运行参数及其值; 可重复使用多次;
-r param[,param...]: 设定指定的参数为只读状态;
重载vcl配置文件:
~ ]# varnish_reload_vcl
varnishadm
-S /etc/varnish/secret -T [ADDRESS:]PORT
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
配置文件相关:
vcl.list:显示类似于ls命令
vcl.load:装载,加载并编译;
vcl.use:激活;
vcl.discard:删除;
vcl.show [-v] <configname>:查看指定的配置文件的详细信息;
运行时参数:
param.show -l:显示列表;
param.show <PARAM>
param.set <PARAM> <VALUE>
缓存存储:
storage.list
后端服务器:
backend.list
VCL:
”域“专有类型的配置语言;
state engine:状态引擎;
VCL有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离;每个状态引擎可使用return(x)指明关联至哪个下一级引擎;每个状态引擎对应于vcl文件中的一个配置段,即为subroutine
vcl_hash --> return(hit) --> vcl_hit
vcl_recv的默认配置:
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
}
Client Side:
vcl_recv, vcl_pass, vcl_hit, vcl_miss, vcl_pipe, vcl_purge, vcl_synth, vcl_deliver
vcl_recv:
hash:vcl_hash
pass: vcl_pass
pipe: vcl_pipe
synth: vcl_synth
purge: vcl_hash --> vcl_purge
vcl_hash:
lookup:
hit: vcl_hit
miss: vcl_miss
pass, hit_for_pass: vcl_pass
purge: vcl_purge
Backend Side:
vcl_backend_fetch, vcl_backend_response, vcl_backend_error
两个特殊的引擎:
vcl_init:在处理任何请求之前要执行的vcl代码:主要用于初始化VMODs;
vcl_fini:所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;
vcl的语法格式:
(1) VCL files start with vcl 4.0;
(2) //, # and /* foo */ for comments;
(3) Subroutines are declared with the sub keyword; 例如sub vcl_recv { ...};
//用sub关键词定义子例程
(4) No loops, state-limited variables(受限于引擎的内建变量);
//不支持循环,
(5) Terminating statements with a keyword for next action as argument of the return() function, i.e.: return(action);用于实现状态引擎转换;
(6) Domain-specific;
//特定的领域
The VCL Finite State Machine
//VCL有限状态机
(1) Each request is processed separately;
//每个请求是分开处理的
(2) Each request is independent from others at any given time;
//每个请求在任何给定的时间都是独立于其他请求的
(3) States are related, but isolated;
//即便是有状态、有关联性,但彼此否是隔离的
(4) return(action); exits one state and instructs Varnish to proceed to the next state;
//决定下一跳是哪里
(5) Built-in VCL code is always present and appended below your own VCL;
三类主要语法:
sub subroutine {
...
}
if CONDITION {
...
} else {
...
}
return(), hash_data()
VCL Built-in Functions and Keywords
函数:
regsub(str, regex, sub)
regsuball(str, regex, sub)
ban(boolean expression)
hash_data(input)
synthetic(str)
Keywords:
call subroutine, return(action),new,set,unset
操作符:
==, !=, ~, >, >=, <, <=
逻辑操作符:&&, ||, !
变量赋值:=
实例:obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次
102.70:varnish
vim /etc/varnish/default.vcl /在最后结尾处定义
if (obj.hits > 0) {
set resp.http.X-Varnish = "Hit via " + server.ip;
} else {
set resp.http.X-Varnish = "Miss from " + server.ip;
}
用于加载default.val文件中添加的内容:
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
//可获取帮助:help
vcl.load conf1 default.vcl //编译成功了 conf1:名字随意 default.vcl:文件
200
VCL compiled.
vcl.use conf1 //使用加载conf1
200
VCL ‘conf1‘ now active
vcl.discard //用于删除 后面跟上要删除的内容即可;
测试:google:172.20.102.70:6081
打开开发工具:显示刚才定义的内容
Via:1.1 varnish-v4
X-Varnish:Hit via 172.20.102.70
测试级:102.71
wget http://172.20.102.70:6081 //可将102.70的网站页面能下载下来
wget -O - -q http://172.20.102.70:6081 //查看此网站的内容
问题:拒绝它访问:
102.70:varnish
vim /etc/varnish/default.vcl //在 sub vcl_recv 处定义将它拒绝访问
sub vcl_recv {
if(req.http.User-Agent ~ "curl") {
return(synth(403));
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
varnish> vcl.load conf2 default.vcl
200
VCL compiled.
vcl.list
200
available 0 boot
active 0 conf1
available 0 conf2
vcl.use conf2
200
VCL ‘conf2‘ now
测试机:102.71:
curl http://172.20.102.70:6081 //将会显示拒绝访问
问题:如有人访问admin的URL时直接拒绝访问:
126.180:http服务:
mkdir -pv /var/www/html/admin
vim /var/www/html/admin/index.html
admin
102.70:varnish
vim /etc/varnish/default.vcl //跟在刚才定义的curl内容后面即可
if(req.url ~ "^/admin") {
return(synth(403));
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf2 default.vcl
200
VCL compiled.
vcl.use conf2
200
VCL ‘conf2‘ now active
测试机:
wget -O - -q http://172.20.102.70:6081/admin //将无法使用admin的url的路径
变量类型:
内建变量:
req.*:request,表示由客户端发来的请求报文相关;
req.http.*
req.http.User-Agent, req.http.Referer, ...
bereq.*:由varnish发往BE主机的httpd请求相关;
bereq.http.*
beresp.*:由BE主机响应给varnish的响应报文相关;
beresp.http.*
resp.*:由varnish响应给client相关;
obj.*:存储在缓存空间中的缓存对象的属性;只读;
常用变量:
bereq.*, req.*:
bereq.http.HEADERS
bereq.request, req.request:请求方法;
bereq.url, req.url:请求的url;
bereq.proto:请求的协议版本;
bereq.backend:指明要调用的后端主机;
req.http.Cookie:客户端的请求报文中Cookie首部的值;
req.http.User-Agent ~ "chrome"
beresp.*, resp.*:
beresp.http.HEADERS
beresp.status, resp.status:响应的状态码;
reresp.proto, resp.proto:协议版本;
beresp.backend.name:BE主机的主机名;
beresp.ttl:BE主机响应的内容的余下的可缓存时长;
obj.*
obj.hits:此对象从缓存中命中的次数;
obj.ttl:对象的ttl值
server.*
server.ip:varnish主机的IP;
server.hostname:varnish主机的Hostname;
client.*
client.ip:发请求至varnish主机的客户端IP;
用户自定义:
set
unset
示例1:强制对某类资源的请求不检查缓存:
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") { //请求的url如果是login或者是admin
return(pass); //不检查缓存
}
}
102.70:
vim /etc/varnish/default.vcl //修改内容
if(req.url ~ "^/admin") {
return(pass); //不缓存
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf6 default.vcl
vcl.use conf6
测试:Google:172.20.102.70:6081/admin 启用开发工具
Via:1.1 varnish-v4
X-Varnish:Miss from 172.20.102.70 //没有缓存
示例2:对于特定类型的资源,例如公开的图片等,取消其私有标识,并强行设定其可以由varnish缓存的时长; 定义在vcl_backend_response中;
if (beresp.http.cache-control !~ "s-maxage") { //后端服务发的的响应报文 首部名称:cache-control !~:不匹配不到 s-maxage
if (bereq.url ~ "(?i).(jpg|jpeg|png|gif|css|js)$") { //静态内容
unset beresp.http.Set-Cookie; //取消后端服务器发来的Set-Cookie
set beresp.ttl = 3600s; //强行将静态内容过期时间 为1小时
}
}
注意:出现这样情况需手动清理缓存
示例3:定义在vcl_recv中;
vim /etc/varnish/default.vcl
if (req.restarts == 0) { //请求被重启的
if (req.http.X-Fowarded-For) { //请求报文中
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf5 default.vcl
200
VCL compiled.
vcl.use conf5
200
VCL ‘conf5‘ now active
126.180:http服务
vim /etc/httpd/conf/httpd.conf
<IfModule log_config_module>
LogFormat "%{X-Forwarded-For}i %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
systemctl restart httpd.service
缓存对象的修剪:purge, ban
配置purge操作:
(1) 能执行purge操作
sub vcl_purge {
return (synth(200,"Purged"));
}
(2) 何时执行purge操作
sub vcl_recv {
if (req.method == "PURGE") {
return(purge);
}
...
}
实例:配置purge:
102.70:
vim /etc/varnish/default.vcl //sub vcl_recv中配置
if (req.method == "PURGE") {
return(purge);
}
sub vcl_purge {
return(synth(200,"Ok."));
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf6 default.vcl
200
VCL compiled.
vcl.use conf6
200
VCL ‘conf6‘ now active
测试:curl -I http://172.20.102.70:6081
添加此类请求的访问控制法则:
acl purgers {
"127.0.0.0"/8;
"10.1.0.0"/16;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return(synth(405,"Purging not allowed for " + client.ip));
}
return(purge);
}
...
}
实例:基于acl请求访问控制:
acl不属于任何子进程
102.70:varnish
vim /etc/varnish/default.vcl //在backend default { 中定义
acl purgers {
"127.0.0.0"/8;
}
if (req.method == "PURGE") {
if (client.ip ~ purgers) {
return(purge);
} else {
return(synth(403,"not allowed for " + client.ip));
}
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf7 default.vcl
200
VCL compiled.
vcl.use conf7
200
VCL ‘conf7‘ now active
测试:客户端:
curl -I http://172.20.102.70:6081
curl -X PURGE http://172.20.102.70:6081
<!DOCTYPE html>
<html>
<head>
<title>403 not allowed for 172.20.102.71</title>
</head>
<body>
<h1>Error 403 not allowed for 172.20.102.71</h1>
<p>not allowed for 172.20.102.71</p>
<h3>Guru Meditation:</h3>
<p>XID: 131133</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
varnish服务:
curl -X PURGE http://127.0.0.1:6081
<!DOCTYPE html>
<html>
<head>
<title>200 Ok.</title>
</head>
<body>
<h1>Error 200 Ok.</h1>
<p>Ok.</p>
<h3>Guru Meditation:</h3>
<p>XID: 131135</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
Banning:
(1) varnishadm:
ban <field> <operator> <arg>
示例:
ban req.url ~ (?i)^/javascripts
实例:不区分字符大小写:
126.180:http
mkdir -pv /var/www/html/ja
vim /var/www/html/ja/j.txt
j.txt
102.70:varnish
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
ban req.url ~ (?i)^/ja
200
(2) 在配置文件中定义,使用ban()函数;
示例:
if (req.method == "BAN") {
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
# Throw a synthetic page so the request won‘t go to the backend.
return(synth(200, "Ban added"));
}
curl -X BAN http://www.ilinux.io/test1.html
ban req.http.host==www.ilinux.io && req.url==/test1.html
如何设定使用多个后端主机:
backend default {
.host = "172.16.100.6";
.port = "80";
}
backend appsrv {
.host = "172.16.100.7";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "(?i).php$") {
set req.backend_hint = appsrv;
} else {
set req.backend_hint = default;
}
...
}
nginx: proxy_pass
haproxy: use_backend
实例:使用负载均衡机制,实现多个后台主机:
172.20.126.180:http
cd /var/www/html/
for i in {1..10}; do echo "test $i" > test$i.txt; done
scp -rp * [email protected]:/var/www/html/
systemctl restart httpd
172.20.128.17:http
systemctl start httpd
172.20.102.70:varnish
vim /etc/varnish/default.vcl
import directors;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "172.20.126.180";
.port = "80";
}
backend srv1 {
.host = "172.20.126.180";
.port = "80";
}
backend srv2 {
.host = "172.20.128.17";
.port = "80";
}
sub vcl_init {
new websrvs = directors.round_robin();
websrvs.add_backend(srv1);
websrvs.add_backend(srv2);
}
acl purgers {
"127.0.0.0"/8;
"172.20.102.71"/32;
}
sub vcl_recv {
set req.backend_hint = websrvs.backend();
}
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
vcl.load conf9 default.vcl
200
VCL compiled.
varnish> vcl.use conf9
200
VCL ‘conf9‘ now active
测试:客户端
for i in {1..10}; do curl -I -s http://172.20.102.70:6081/test$i.txt ; done //第一次无法生成缓存 第二次可以
Director:
varnish module;
使用前需要导入:
import directors;
示例:
import directors; # load the directors
backend server1 {
.host =
.port =
}
backend server2 {
.host =
.port =
}
sub vcl_init {
new GROUP_NAME = directors.round_robin();
GROUP_NAME.add_backend(server1);
GROUP_NAME.add_backend(server2);
}
sub vcl_recv {
# send all traffic to the bar director:
set req.backend_hint = GROUP_NAME.backend();
}
基于cookie的session sticky:
sub vcl_init {
new h = directors.hash();
h.add_backend(one, 1); // backend ‘one‘ with weight ‘1‘
h.add_backend(two, 1); // backend ‘two‘ with weight ‘1‘
}
sub vcl_recv {
// pick a backend based on the cookie header of the client
set req.backend_hint = h.backend(req.http.cookie);
}
基于随机的调度方式,支持服务器权重:
sub vcl_init {
new websrvs = directors.random();
websrvs.add_backend(srv1,1);
websrvs.add_backend(srv2,2);
}
BE Health Check:
backend BE_NAME {
.host =
.port =
.probe = {
.url=
.timeout=
.interval=
.window=
.threshold=
}
}
10, 8
.probe:定义健康状态检测方法;
.request:发出的具体请求;
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close"
.window:基于最近的多少次检查来判断其健康状态;
.threshold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;
.interval:检测频度;
.timeout:超时时长;
.expected_response:期望的响应码,默认为200;
健康状态检测的配置方式:
(1) probe PB_NAME { }
backend NAME = {
.probe = PB_NAME;
...
}
(2) backend NAME {
.probe = {
...
}
}
示例:
probe check {
.url = "/.healthcheck.html";
.window = 5;
.threshold = 4;
.interval = 2s;
.timeout = 1s;
}
backend default {
.host = "10.1.0.68";
.port = "80";
.probe = check;
}
backend appsrv {
.host = "10.1.0.69";
.port = "80";
.probe = check;
}
手动设定BE主机的状态:
sick:管理down;
healthy:管理up;
auto:probe auto;
设置后端的主机属性:
backend BE_NAME {
...
.connect_timeout = 0.5s;
.first_byte_timeout = 20s;
.between_bytes_timeout = 5s;
.max_connections = 50;
}
varnish的运行时参数:
线程模型:
cache-worker
cache-main
ban lurker
acceptor:
epoll/kqueue:
...
线程相关的参数:使用线程池机制管理线程;
在线程池内部,其每一个请求由一个线程来处理; 其worker线程的最大数决定了varnish的并发响应能力;
thread_pools:Number of worker thread pools. 最好小于或等于CPU核心数量;
thread_pool_max:The maximum number of worker threads in each pool. 每线程池的最大线程数;
thread_pool_min:The minimum number of worker threads in each pool. 额外意义为“最大空闲线程数”;
最大并发连接数 = thread_pools * thread_pool_max
thread_pool_timeout:Thread idle threshold. Threads in excess of thread_pool_min, which have been idle for at least this long, will be destroyed.
thread_pool_add_delay:Wait at least this long after creating a thread.
thread_pool_destroy_delay:Wait this long after destroying a thread.
Timer相关的参数:
send_timeout:Send timeout for client connections. If the HTTP response hasn‘t been transmitted in this many seconds the session is closed.
timeout_idle:Idle timeout for client connections.
timeout_req: Max time to receive clients request headers, measured from first non-white-space character to double CRNL.
cli_timeout:Timeout for the childs replies to CLI requests from the mgt_param.
设置方式:
vcl.param
param.set
永久有效的方法:
varnish.params
DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"
实例:
102.70:varnish
vim /etc/varnish/varnish.params
Other options, see the man page varnishd(1) //默认注释
DAEMON_OPTS="-p thread_pools=4 -p thread_pool_min=50 -p thread_pool_max=2000 -p thread_pool_timeout=300"
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
param.set thread_pools 4
200
varnish日志区域:
shared memory log
计数器
日志信息
1、varnishstat - Varnish Cache statistics
-1
-1 -f FILED_NAME
-l:可用于-f选项指定的字段名称列表;
MAIN.cache_hit
MAIN.cache_miss
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
显示指定参数的当前统计数据;
# varnishstat -l -f MAIN -f MEMPOOL
列出指定配置段的每个参数的意义;
2、varnishtop - Varnish log entry ranking
-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;
-I <[taglist:]regex>:对指定的标签的值基于regex进行过滤;
-x taglist:排除列表
-X <[taglist:]regex>:对指定的标签的值基于regex进行过滤,符合条件的予以排除;
3、varnishlog - Display Varnish logs
4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format
内建函数:
hash_data():指明哈希计算的数据;减少差异,以提升命中率;
regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite
regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;
return():
ban(expression)
ban_url(regex):Bans所有的其URL可以被此处的regex匹配到的缓存对象;
synth(status,"STRING"):生成响应报文;
总结:
varnish: state engine, vcl
varnish 4.0:
vcl_init
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_pipe
vcl_waiting
vcl_purge
vcl_deliver
vcl_synth
vcl_fini
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
sub VCL_STATE_ENGINE {
...
}
backend BE_NAME {}
probe PB_NAME {}
acl ACL_NAME {}
以上是关于varnish详解的主要内容,如果未能解决你的问题,请参考以下文章