Jusene's Blog

varnish 缓存为王

字数统计: 2.5k阅读时长: 11 min
2017/05/30 Share

varnish

varnish是一款高性能的开源http缓存加速器,缓存服务器我们最常见的是squid,这是一款较早期的较重量级的缓存的服务器,varnish与squid的关系就像现在的nginx和httpd的关系,现在nginx已经被广泛的接受了,所以相信varnish在未来的前途还是很可观的,在如今的互联网系统中,有太多的系统架构是依赖缓存服务器的,所以在整个系统架构中缓存是关键的一环,现在的互联网时代缓存为王,但想要管理好缓存也并不是容易办到的,缓存数据我们需要通过内核操控内存的中的数据,这对我们来说本身不可见,我们只能通过不断调试测试来完成缓存工作。

http cache

程序运行具有局部性特征:时间局部性,空间局部性,即每个程序在特定时间运行会较为频繁,当该时间点运行完的数据在下一刻可能仍会被需要运行,在该节点运行的数据,其周边的节点的运行的数据也会较为频繁。所以整个程序的运行是具有热点数据的,如果我们可以在整个系统中将热点数据进行缓存处理,那么整个系统中后端服务器的处理能力将会有指数级增长。

为了评定缓存的能力,我们有缓存命中率的评定标准(hit/(hit+miss)),缓存的命中率存在两种评定标准:
(1)文档的命中率:从命中的文档个数进行衡量
(2)字节的命中率:从命中的内容的大小进行衡量

对于缓存的整个处理步骤:

接受请求–>解析请求(提取请求的url及各种头部)–>查询缓存–>新鲜度检测–>构建响应报文–>发送响应–>记录日志

缓存控制机制:

1
HTTP/1.0 Expires
2
	Expires: Fri,20,May 2017 02:03:18 GMT  #过期时间
3
HTTP/1.1 Cache-Control: max-age
4
	Cache-Control: no transform,max-age=3600  #相对时间,保存3600
5
		cache-request-directive=
6
				no-cache
7
				no-store
8
				max-age
9
				max-stale
10
				min-fresh
11
		cache-response-directive=
12
				public
13
				private
14
				no-cache
15
				no-store
16
				must-revalidate
17
				max-age
18
				s-max-age

新鲜度检测机制:

  • 有效性再验证:revalidate
    如果原始内容未改变,则仅响应首部(不用附带body部分):响应码为304(not modified)
    如果原始内容发生了改变,则正常响应,响应码为200
    如果原始内容消失,则响应为404,此时缓存中的缓存项也应该被删除
  • 条件式请求首部
    If-Modified-Since: 基于原始内容的最近一个修改的时间戳进行
    If-Unmodified-Since:
    If-Match
    If-None-Match:基于Etag的比较进行

varnish进程特性

varnish的工作模式需要通过management提高的管理接口,通过vcl编程编译成c语言,再通过c编译成子进程可以识别的共享对象来进行配置。

  • 安装
1
~]# yum install -y epel-release
2
~]# yum install -y varnish
  • 配置varnish进程参数
1
~]# cat /etc/varnish/varnish.params
2
RELOAD_VCL=1                                        #是否运行reload
3
VARNISH_VCL_CONF=/etc/varnish/default.vcl           #vcl配置文件
4
# VARNISH_LISTEN_ADDRESS=192.168.1.5                #监听的ip
5
VARNISH_LISTEN_PORT=80                              #监听的端口
6
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1              #管理的ip
7
VARNISH_ADMIN_LISTEN_PORT=6082                      #管理的端口
8
VARNISH_SECRET_FILE=/etc/varnish/secret             #认证文件
9
VARNISH_STORAGE="malloc,256M"                       #varnish存储对象
10
#VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G"  #varnish存储对象
11
VARNISH_USER=varnish                                #varnish启动的用户
12
VARNISH_GROUP=varnish                               #varnish启动的用户组
13
#DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"  #其他选项
14
15
16
~]# cat /usr/lib/systemd/system/varnish.service
17
...
18
ExecStart=/usr/sbin/varnishd \
19
        -P /var/run/varnish.pid \
20
        -f $VARNISH_VCL_CONF \
21
        -a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
22
        -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
23
        -S $VARNISH_SECRET_FILE \
24
        -s $VARNISH_STORAGE \
25
        $DAEMON_OPTS
26
...

varnish的存储对象:

  • (1)file :自管理的文件系统,黑盒:

  • (2)malloc:使用malloc()库调用在varnish启动时向内存申请指定大小的空间

  • (3)persistent:与file功能相同;仍处于测试期

  • 启动varnish

1
~]# systemctl start varnish.service

vcl

vcl是一种‘域‘专用的编程语言,vcl存在多个状态引擎,通过return的返回值来退出当前状态,并进入下个状态,彼此间状态相互联系,但彼此间又相互隔离,不同的状态引擎,其返回状态都不相同。

varnish的状态引擎:

1
vcl_recv
2
vcl_hash
3
	hit:vcl_hit
4
	miss:vcl_miss
5
	purge:vcl_purge
6
	pipe:vcl_pipe
7
	pass,hit_for_pass:vcl_pass
8
vcl_backend_fetch
9
vcl_backend_response
10
vcl_backend_error
11
12
vcl_synth
13
14
vcl_deliver

各个状态引擎的关系如下图:


数据报文大致流向:

1
vcl_recv-->vcl_hash-->
2
		(1)vcl_hit-->
3
				(a)vcl_deliver
4
				(b)vcl_pass
5
		(2)vcl_miss-->
6
				(a)vcl_pass
7
				(b)vcl_backend_fetch
8
		(3)vcl_purge-->
9
				(a)vcl_synth
10
				(4)vcl_pipe-->
11
vcl_pass-->
12
		vcl_backend_fetch
13
vcl_backend_fetch-->
14
		vcl_backend_response-->vcl_deliver
15
		vcl_backend_error

vcl编程

varnish做反代,请求后端服务器

测试信息:

1
~]# cat /etc/varnish/default.vcl
2
vcl 4.0;
3
backend default {
4
    .host = "10.211.55.43";
5
    .port = "80";
6
}
7
sub vcl_deliver {
8
	if (obj.hits>0) {
9
        set resp.http.X-Cache = "HIT" + " " + server.ip;
10
    } else {
11
        set  resp.http.X-Cache = "MISS" + " " + server.ip;
12
	}
13
}

内建变量:

1
req.*: 客户端请求
2
req.http.*:客户端请求报文首部
3
bereq.*: 由varnish向backend主机发出的http请求
4
beresp.*:由backend主机发来的http响应报文
5
resp.*:varnish响应client的http响应报文
6
resp.http.*: 响应报文各首部的值
7
obj.*:对缓存在缓存空间中的缓存对象属性,只读
8
9
client.*,server.*,storage.*: 可用在所有client side的sub routines中

自定义变量:set

常用的变量:
bereq.http.HEADERS
bereq.request: 请求方法
bereq.url:请求的url
bereq.poro: 协议版本
bereq.backend: 指明要调用的后端主机

beresp.poro
beresp.status: 响应的状态码
beresp.reason
beresp.backend.name
beresp.http.HEADERS
beresp.ttl:后端服务器响应内容的余下的生存时间

obj.hits: 此对象从缓存中命中的次数
obj.ttl: 对象ttl值

server.ip
server.hostname

req.method:请求方法
req.url:请求的url

实例1

强制对某资源请求不检查缓存:

1
vcl 4.0;
2
backend default {
3
    .host = "10.211.55.43";
4
    .port = "80";
5
}
6
sub vcl_recv {
7
	if(req.url ~ "(?!)/admin | (?!)/login") {
8
		return(pass)
9
	}
10
}

varnish不能随便重启,我们需要通过管理接口重新加载配置:

1
~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
2
200        
3
-----------------------------
4
Varnish Cache CLI 1.0
5
-----------------------------
6
Linux,3.10.0-514.16.1.el7.x86_64,x86_64,-smalloc,-smalloc,-hcritbit
7
varnish-4.0.4 revision 386f712
8
9
Type 'help' for command list.
10
Type 'quit' to close CLI session.
11
12
vcl.load test /etc/varnish/default.vcl
13
200        
14
VCL compiled.
15
16
vcl.use test
17
200        
18
VCL 'test5' now active

实例2

对公开的图片取消其私有标识,并强行通过varnish修改的时长

1
vcl 4.0;
2
backend default {
3
    .host = "10.211.55.43";
4
    .port = "80";
5
}
6
7
sub vcl_backend_response {
8
	if(beresp.http.cache-control !~ 's-maxage') {
9
		if(bereq.url ~ "(?!)\.jpg$") {
10
			set beresp.ttl = 7200s;
11
			unset beresp.http.Set-Cookie;
12
		}
13
		if(bereq.url ~ "(?!)\.css") {
14
			set beresp.ttl = 3600s;
15
			unset beresp.http.Set-Cookie;
16
		}
17
	}
18
}

实例3

缓存修剪

1
vcl 4.0;
2
backend default {
3
    .host = "10.211.55.43";
4
    .port = "80";
5
}
6
7
acl purgers {
8
	"127.0.0.1";
9
	"10.211.55.0"/24;
10
}
11
12
sub vcl_recv {
13
	if(req.method == "PURGE") {
14
        if(!client.ip ~ purgers) {
15
            return(synth(405,"purger not to alloed to " + client.ip));
16
		}
17
        return(purge);
18
	}
19
}
20
21
sub vcl_purge {
22
    return(synth(200,"purged"));
23
}

测试:

1
~]# curl -X PURGE http://10.211.55.39
2
<!DOCTYPE html>
3
<html>
4
  <head>
5
    <title>200 purged</title>
6
  </head>
7
  <body>
8
    <h1>Error 200 purged</h1>
9
    <p>purged</p>
10
    <h3>Guru Meditation:</h3>
11
    <p>XID: 32791</p>
12
    <hr>
13
    <p>Varnish cache server</p>
14
  </body>
15
</html>
16
17
不在acl列表中使用purge
18
~]# curl -X PURGE http://10.211.55.39
19
<!DOCTYPE html>
20
<html>
21
  <head>
22
    <title>405 purger not to alloed to 10.212.55.43</title>
23
  </head>
24
  <body>
25
    <h1>Error 405 purger not to alloed to 10.212.55.43</h1>
26
    <p>purger not to alloed to 10.212.55.43</p>
27
    <h3>Guru Meditation:</h3>
28
    <p>XID: 32799</p>
29
    <hr>
30
    <p>Varnish cache server</p>
31
  </body>
32
</html>

实例4

设定多个后端主机

1
vcl 4.0;
2
backend default {
3
		.host="10.211.55.34",
4
		.port="80",
5
}
6
7
backend appser {
8
		.host="10.211.55.35";
9
		.port="80";
10
}
11
12
sub vcl_recv {
13
		if(req.url ~ "(?!)\.php$") {
14
			set req.backend_hint = appser;
15
		} else {
16
			set req.backend_hint = default;
17
		}
18
}

实例5

负载均衡器

1
vcl 4.0;
2
import directors
3
4
backend default {
5
	.host="10.211.55.34";
6
	.port="80";
7
	.probe={
8
		.url="/";
9
		.interval=1s;
10
		.window=8;
11
		.threshold=5;
12
		.timeout=2s;
13
	}
14
}
15
16
backend appser {
17
	.host="10.211.55.35";
18
	.port="80";
19
	.probe={
20
		.url="/";
21
		.interval=1s;
22
		.window=8;
23
		.threshold=5;
24
		.timeout=2s;
25
	}
26
}
27
28
sub vcl_init {
29
	new bar=directors.round_robin();
30
	bar.add_backend(default);
31
	bar.add_backend(appser);
32
}
33
34
sub vcl_recv {
35
	set req.backend_hint=bar.backend();
36
}

测试:

1
~]# curl 10.211.55.39
2
nginx1
3
~]# curl 10.211.55.39
4
nginx2

varnish常用的命令行工具

varnishadm: varnish命令行管理接口
varnishtop: varnish实时请求状态查看
varnishncsa: varnish格式化请求日志查看,默认在内存中只有90m的存储空间,需要实时写入存储,可以启动varnishncsa.service
varnishlog: varnish原始日志查看,可以启动varnishlog写入存储
varnishstat: varnish状态查看

参考资料:http://www.varnish-cache.org

CATALOG
  1. 1. varnish
  2. 2. http cache
  3. 3. varnish进程特性
  4. 4. vcl
    1. 4.1. vcl编程
    2. 4.2. 实例1
    3. 4.3. 实例2
    4. 4.4. 实例3
    5. 4.5. 实例4
    6. 4.6. 实例5
  5. 5. varnish常用的命令行工具