- 博客/
varnish缓存服务器的配置
Varnish简介#
Varnish是一款高性能且开源的反向代理服务器和 HTTP 加速器,支持采用基于linux系统内存的缓存服务器。
varnish的系统架构如下图:
- varnish是主要运行两个进程:Management进程和Child进程(也叫Cache进程),基于 epoll机制的单进程多线程架构
- Management进程类似于nginx中的master,主要实现 编译VCL并应用新配置(通知子进程);监控varnish格子进程运行状态,初始化varnish; 提供一个CLI接口(命令行接口)指挥管理进程 等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。
- Child进程包含多种类型的线程,常见的如:
- Acceptor线程:接收新的连接请求并响应
- Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多
- Expiry线程:从缓存中清理过期内容
- varnish通过使用VCL(Varnish Configuration Language )配置缓存系统的缓存策略,VCL编译器调用C编译器,C编译器编译配置文件为二进制文件并连接至child进程。
VCL语法格式
(1)//、#或/* comment */用于注释 (2)sub $name 定义函数 (3)不支持循环,有内置变量 (4)使用终止语句,没有返回值 (5)域专用 (6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)
三类主要语法:
sub subroutine {
...
}
if CONDITION {
...
} else {
...
}
return(), hash_data()
- Varnish状态引擎(state engine)
varnish内部有几个所谓的状态(state),在这些状态上可以附加通过VCL定义的策略以完成相应的缓存处理机制,因此VCL也经常被称作“域专用”语言或状态引擎,“域专用”指的是有些数据仅出现于特定的状态中。在VCL状态引擎中,状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并联至哪个下一级引擎;每个状态引擎对应于vcl文件(default.vcl)中的一个配置段,即为subroutine。例如:
vcl_recv – 处理客户端请求的第一步,分析是否为标准HTTP请求,是否为可缓存资源等
vcl_synth – 用于合成响应报文
vcl_purge – 用于删除某条缓存记录
vcl_backend_fetch – 根据服务器端的响应作出缓存决策(eg:是否先缓存再响应给客户端)
vcl_pass – 不能缓存的请求跳转到vcl_backend_fetch状态
两个特殊的引擎: vcl_init – 在处理任何请求之前要执行的vcl代码:主要用于初始化加载额外模块;vcl配置文件中要先于vcl_recv定义 vcl_fini – 所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;
- 变量
在vcl配置文件中指定缓存规则时,可以引用变量,包括内建变量与自定义变量
- 内建变量:
req.*:request,表示由客户端发来的请求报文相关
req.http.*
req.http.User-Agent 客户端设备类型
req.http.Referer 超链接跳转地址
bereq.*:由varnish发往BE主机请求报文相关
bereq.http.*
beresp.*:由BE主机响应给varnish的响应报文相关
beresp.http.*
resp.*:由varnish响应给client相关
obj.*:存储在缓存空间中的缓存对象的属性;只读
server.*
server.ip:varnish主机的IP
server.hostname:varnish主机的Hostname
client.*
client.ip:发请求至varnish主机的客户端IP
- 自定义变量
set/unset
详情请参考https://varnish-cache.org/docs/4.0/
varnish安装与配置#
使用yum源安装varnish
$ yum install -y varnish
配置文件:
/etc/varnish/varnish.params
–> 配置varnish服务进程的工作特性VARNISH_LISTEN_PORT=6081 – varnish 服务进程监听的端口
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
varnishadm命令行工具连入CLI接口的地址与端口
VARNISH_STORAGE=“malloc,1024M”
varnish的缓存存储机制( Storage Types):
malloc[,size] — 内存存储,[,size]用于定义空间大小;重启后所有缓存项失
file[,path[,size[,granularity]]] — 磁盘文件存储,黑盒;重启后所有缓存项失效
persistent,path,size — 文件存储,黑盒;重启后所有缓存项有效;实验阶段
DAEMON_OPTS="-P thread_pools=2 -p thread_pool_max=1000 thread_pool_timeout=300"
指定varnish的运行时参数thread、timer相关
- 配置文件:
/etc/varnish/default.vcl
–>配置各Child/Cache线程的缓存策略
结合一下示例来熟悉vcl配置:
- 使用内建变量obj.hits(用于保存某缓存项的从缓存中命中的次数)在响应报文中添加缓存标记
$ vim /etc/varnish/default.vcl
backend default { <-- 定义后端服务器监听的IP与端口
.host = "192.168.196.132";
.port = "80";
}
sub vcl_deliver {
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via " + server.ip;
} else {
set resp.http.X-Cache = "MISS from " + server.ip;
}
}
$ varnish_reload_vcl <--自动加载cmd
Loading vcl from /etc/varnish/default.vcl
Current running config name is
Using new config name reload_2017-09-07T16:02:29
VCL compiled.
VCL 'reload_2017-09-07T16:02:29' now active
available 0 boot
active 0 reload_2017-09-07T16:02:29 <--当期使用的版本
Done
浏览器中访问http://192.168.196.133:6081
,刷新之后,从响应报文的X-Cache字段可以看出请求的资源是否被缓存
- 强制对某类资源的请求不检查缓存(eg:用户私有数据)
$ vim /etc/varnish/default.vcl
vcl_recv {
if (req.url ~ "(?i)^/(login|admin)") { <-- /login与/admin目录下均不能缓存
return(pass);
}
}
$ varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 <-- 使用varnishadm工具手动reload配置文件
vcl.list
200
available 0 boot
active 0 reload_2017-09-07T16:02:29
vcl.load test1 default.vcl
200
VCL compiled.
vcl.use test1
200
VCL 'test1' now active
浏览器中访问http://192.168.196.133:6081/login
,无论如何刷新,X-Cache字段均显示’MISS from 192.168.196.133'
- 缓存对象的修剪 –> 在缓存有限期内,后端服务端资源更新时就需要手动删除缓存
- purge 一次删除一条缓存记录
$ vim /etc/varnish/default.vcl
acl purgers { <--只允许acl内的IP能使用purge方法
"127.0.0.0"/8; <--必须以127.0.0.1为client发出请求才符合此acl
"192.168.196.130";
}
vcl_recv {
if (req.method == "PURGE") { <--自定义请求方法PURGE时转到vcl_purge
if (!client.ip ~ purgers) {
return(synth(405,"Purging not allowed for " + client.ip));
}
return(purge);
}
}
reload之后在客户端192.168.196.130上使用curl命令测试
$ curl -I http://192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 12:57:43 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 32819 32817
Age: 2
Via: 1.1 varnish-v4
X-Cache: HIT via 192.168.196.133 <--已缓存
Connection: keep-alive
$ curl -X PURGE http://192.168.196.133:6081 <--定义请求方法为PURGE
<!DOCTYPE html>
<html>
<head>
<title>200 Purged</title>
</head>
<body>
<h1>Error 200 Purged</h1>
<p>Purged</p>
<h3>Guru Meditation:</h3>
<p>XID: 131101</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
[root@Centos7 varnish]# curl -I http://192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 13:01:10 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 32821
Age: 0
Via: 1.1 varnish-v4
X-Cache: MISS from 192.168.196.133 <--未到过期时间,已经没有缓存
Connection: keep-alive
$ curl -X PURGE 192.168.196.133:6081 <--客户端192.168.196.132中访问
<!DOCTYPE html>
<html>
<head>
<title>405 Purging not allowed for 192.168.196.132</title> <--132不在acl定义中,没有权限
</head>
<body>
<h1>Error 405 Purging not allowed for 192.168.196.132</h1>
<p>Purging not allowed for 192.168.196.132</p>
<h3>Guru Meditation:</h3>
<p>XID: 32833</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
Banning
- 使用varnishadm工具删除
ban
$ varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
ban req.url ~ ^/images <-- 将images开头的请求的缓存,全部删除
- 在配置文件中定义,使用ban()函数
$ vim /etc/varnish/default.vcl
acl bans {
"127.0.0.0"/8;
"192.168.196.130";
}
if (req.method == "BAN" ){
if (!client.ip ~ bans){
return(synth(405,"Ban not allowed for " + client.ip));
}
#将请求的资源删除。请求什么,删什么
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200,"Ban succeed"));
}
reload之后在客户端192.168.196.130上使用curl命令测试
$ curl -I 192.168.196.133:6081
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 07 Sep 2017 13:41:13 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Tue, 05 Sep 2017 07:38:56 GMT
ETag: "59ae5490-11"
X-Varnish: 131127 32840
Age: 2
Via: 1.1 varnish-v4
X-Cache: HIT via 192.168.196.133
$ curl -X BAN 192.168.196.133:6081 <--定义请求方法为BAN
<!DOCTYPE html>
<html>
<head>
<title>200 Ban succeed</title>
</head>
<body>
<h1>Error 200 Ban succeed</h1>
<p>Ban succeed</p>
<h3>Guru Meditation:</h3>
<p>XID: 131129</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
$ curl -X BAN 192.168.196.133:6081 <--客户端192.168.196.132中访问
<!DOCTYPE html>
<html>
<head>
<title>405 Ban not allowed for 192.168.196.132</title>
</head>
<body>
<h1>Error 405 Ban not allowed for 192.168.196.132</h1>
<p>Ban not allowed for 192.168.196.132</p>
<h3>Guru Meditation:</h3>
<p>XID: 131144</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
- 调度多个后端主机的设定
- varnish服务器的设定
$ vim /etc/varnish/default.vcl
import directors; <--需要先导入directors模块
backend imgsrv1 {
.host = "192.168.196.129";
.port = "80";
}
backend imgsrv2 {
.host = "192.168.196.130";
.port = "80";
}
backend default {
.host = "192.168.196.132";
.port = "80";
}
sub vcl_init { <-- 初始化directors设定,需要在vcl_recv之前
new imgsrvs = directors.round_robin(); <-- 自定义后端集群名字、调度算法
imgsrvs.add_backend(imgsrv1); <-- 指定要调度的后端主机
imgsrvs.add_backend(imgsrv2);
}
sub vcl_recv {
if (req.url ~ "(?i)\.(jpg|png|txt)$"){
set req.backend_hint = imgsrvs.backend(); <-- 对jpg/png/txt访问调度到后端imgsrvs集群
}else{
set req.backend_hint = default;
}
if (req.url ~ "(?i)\.txt$"){ <-- 为看出轮询效果,不缓存.txt文件
return(pass);
}
}
在imgsrv1/imgsrv2根目录上分别创建test.txt
192.168.196.129 –> echo “Backend imgsrv1” > /usr/share/nginx/html/test.txt
192.168.196.130 –> echo “Backend imgsrv2” > /usr/share/nginx/html/test.txt
为了看出后端服务器轮询的调度效果,在vcl配置文件中定义了不缓存.txt结尾的文件,使用curl命令访问
$ while : ; do curl 192.168.196.133:6081/test.txt; sleep 1; done Backend imgsrv1 Backend imgsrv2 Backend imgsrv1 Backend imgsrv2 Backend imgsrv1
- 后端主机健康检测设置
方法一:直接在Backend 下定义.probe 健康状态检测方法
backend BE_NAME {
.host =
.port =
.probe = {
.url= <--检测时要请求的URL,默认为”/"
.timeout= <--超时时长
.interval= <--检测频率
.window= <--基于最近的多少次检查来判断其健康状态
.threshold= <--最近.window次检查中多少次成功才算健康
}
}
方法二:定义probe,然后在各个backend中调用
probe PB_NAME { } <---定义一个probe 再调用
backend NAME = {
.probe = PB_NAME;
...
}
- 在各个后端主机Web服务根目录创建.healthchk.html文件,用作健康检测
- 修改vcl配置文件
$ vim /etc/varnish/default.vcl
probe healthchk{
.url = "/.healthchk.html";
.timeout = 1s;
.interval = 2s;
.window = 5;
.threshold =4;
}
backend imgsrv1 {
.host = "192.168.196.129";
.port = "80";
.probe = healthchk;
}
backend imgsrv2 {
.host = "192.168.196.130";
.port = "80";
.probe = healthchk;
}
backend default {
.host = "192.168.196.132";
.port = "80";
.probe = healthchk;
}
- 在reload之后使用varnishadm工具查看backend状态
$ varnishadm -S secret -T 127.0.0.1:6082
backend.list
200
Backend name Refs Admin Probe
imgsrv1(192.168.196.129,,80) 1 probe Healthy 5/5
imgsrv2(192.168.196.130,,80) 1 probe Healthy 5/5
default(192.168.196.132,,80) 1 probe Healthy 5/5
- 手动停止imgsrv1的nginx web服务,curl命令测试
$ while : ; do curl 192.168.196.133:6081/test.txt;sleep 1; done
Backend imgsrv1
Backend imgsrv2
Backend imgsrv1
Backend imgsrv2
<!DOCTYPE html>
<html>
<head>
<title>503 Backend fetch failed</title>
</head>
<body>
<h1>Error 503 Backend fetch failed</h1>
<p>Backend fetch failed</p>
<h3>Guru Meditation:</h3>
<p>XID: 32828</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
Backend imgsrv2
Backend imgsrv2
Backend imgsrv2
- varnishadm工具查看backend状态, imgsrv1显示为Sick;重启imgsrv1 nginx服务即可恢复
$ varnishadm -S secret -T 127.0.0.1:6082
backend.list
200
Backend name Refs Admin Probe
imgsrv1(192.168.196.129,,80) 1 probe Sick 0/5
imgsrv2(192.168.196.130,,80) 1 probe Healthy 5/5
default(192.168.196.132,,80) 1 probe Healthy 5/5
- 手动设定BE主机的状态
- sick – 手动标记为down
- healthy – 管理up, 永久健康
- auto – probe auto
$ varnishadm -S secret -T 127.0.0.1:6082
backend.set_health imgsrv1 sick
200
backend.list
200
Backend name Refs Admin Probe
imgsrv1(192.168.196.129,,80) 1 sick Healthy 5/5
imgsrv2(192.168.196.130,,80) 1 probe Healthy 5/5
default(192.168.196.132,,80) 1 probe Healthy 5/5
- 后端主机其它属性设置
backend BE_NAME {
...
.connect_timeout = 0.5s; <--注意是TCP连接,不是http连接
.first_byte_timeout = 20s; <--后端主机响应首字节传输超时时间
.between_bytes_timeout = 5s; <--字节传输中间间隔时长
.max_connections = 50; <--最大并发连接数
}
varnish日志#
- varnishlog –Display Varnish logs
实时获取varnish服务器详细的接收请求及响应日志,常用于debug
- varnishncsa - Display Varnish logs in Apache / NCSA combined log format
ncsa格式的日志,使用命令行cmd实时获取
$ varnishncsa
192.168.196.130 - - [09/Sep/2017:13:05:10 +0800] "GET http://192.168.196.133:6081/ HTTP/1.1" 200 25 "-" "curl/7.29.0"
或者使此服务工作于后台记录日志
$ /usr/bin/varnishncsa -a -w /var/log/varnish/varnishncsa.log -D
在Centos7中varnishncsa为单独的服务,启动即可
$systemctl start varnishncsa