varnish4.0简介
Varnish 4.0 简介
Varnish 是一款开源的HTTP加速器和反向代理服务器,它的主要特点有:
(1)是基于内存缓存,重启后数据将消失。
(2)利用虚拟内存方式,io性能好。
(3)支持设置0~60秒内的精确缓存时间。
(4)VCL配置管理比较灵活。
(5)32位机器上缓存文件大小为最大2G。
(6)具有强大的管理功能,例如top,stat,admin,list等。
(7)状态机设计巧妙,结构清晰。
(8)利用二叉堆管理缓存文件,达到积极删除目的。
与Squid服务器相比,Varnish的优点包括:
1、稳定性很高。两者在完成相同负荷的工作时,Squid服务器发生故障的几率要高于Varnish,因为Squid需要经常重启。
2、访问速度更快。采用了“Visual Page Cache”技术,所有缓存数据都直接从内存读取;而Squid是从硬盘读取缓存数据,因此Varnish在访问速度方面会更快。
3、支持更多的并发连接。因为Varnish的TCP连接释放要比Squid快,所以在高并发连接情况下可以支持更多的TCP连接。
4、可以通过管理端口,使用正则表达式批量清除部分缓存,而Squid做不到。
缺点也有:
1、在高并发状态下CPU、I/O和内存等资源开销都高于Squid。
2、进程一旦挂起、崩溃或者重启,缓存数据都会从内存中完全释放,此时所有请求都会被发送到后端服务器,在高并发情况下,这会给后端服务器造成很大压力。
tar -zxvf varnish-4.0.0.tar.gz
cd varnish-4.0.0
./autogen.sh
./configure --prefix=/usr/local/varnish
架构
- 管理进程会定期检查child进程的状态,如果child进程发生异常会被重启,并将错误日志写入syslog;
- 管理进程会解析VCL并转化为C语言,然后由C编译器(如gcc)来编译,编译后的VCL会被链接到正在运行的Varnish实例;
编译后的VCL文件一直被保留直到重启Varnish或通过管理客户端的vcl.discard命令丢弃它。在Varnish不停止运行的情况下,可通过管理客户端重新加载VCL配置,新VLC的缓存策略会立即生效,如下面的例子:
# varnishadm vcl.list
available 0 boot
available 0 reload_2013-04-06T23:00:44
available 0 reload_2013-04-06T23:00:47
available 0 reload_2013-04-06T23:00:48
active 0 reload_2013-04-06T23:00:49
编译一个新的vcl,并加载使用:
# varnishadm vcl.load full_vcl /usr/local/varnish/etc/varnish/full_fdfs.vcl
# varnishadm vcl.list
available 0 boot
available 0 reload_2013-04-06T23:00:44
available 0 reload_2013-04-06T23:00:47
available 0 reload_2013-04-06T23:00:48
active 0 reload_2013-04-06T23:00:49
available 0 full_vcl
# varnishadm vcl.use full_vcl
丢弃一个名为”reload_2013-04-06T23:00:44″ 的vcl配置:
# varnishadm vcl.discard reload_2013-04-06T23:00:44
线程名称 | 线程数目 | 任务 |
acceptor 线程 | 1个 | 接收新连接 |
cache-worker 线程 | 每个会话(活动连接)一个 | 处理请求 |
cache-main 线程 | 1个 | 用于Varnish启动 |
expiry 线程 | 1个 | 将旧内容从缓存中移除 |
ban lurker 线程 | 1个 | 清除bans |
epoll/kqueue 线程 | 可配置,默认为2个 | 管理线程池 |
backend 探测线程 | 每个后端探测有一个 | 健康检查 |
Varnish支持几种方式来给缓存分配空间:
- malloc存储方式,使用malloc 分配整个预设缓存大小的内存,Linux通过使用swap将不能装载到内存的数据存储到磁盘;
- file存储方式,在文件系统上创建一个文件去包含整个缓存,并通过mmap将整个文件映射到内存中,即file方式实际上也是使用内存去缓存数据;
- persistent(仍在试验中),类似file存储方式,是一种试验性的持久存储方式,它还没有很好解决空间全部消耗完的情况;
注意:选择存储方式的时候,如果内存足够大的话,最好选择malloc,这样可以让缓存全部或是大部分保存在内存中;
如果需要缓存的数据超过可用物理内存,可以选择file存储方式。但需要注意的是,在停止或重启Varnish的时候,file存储的方式不会保留数据。使用file存储方式,Varnish不会记录哪些数据写入到磁盘,哪些没有写入,因此不可能知道磁盘上的缓存是否可用,它仅仅是随机数据,如果使用file存储方式的话,Varnish不会重新使用旧的缓存。
VCL
- 块是由花括号分隔,语句以分号结束,使用 '#' 添加注释;
- VCL支持以下运算符:=(赋值),==(对比),~(匹配),!(否定),&&(逻辑与),||(逻辑或);
- 在VCL中,有三个重要的数据结构req(client request)、bereq(backend request)、beresp(backend response)和obj(cache object);
- 两个字符串的连接,它们之间没有任何运算符;
- VCL没有用户自定义的变量,但可以使用set关键字设置变量值,例如set beresp.ttl=5d;
- 使用set关键字设置http头,使用unset关键字移除http头,例如
set req.http.User-Agent = "unknown"; unset req.http.Range;
- VCL有if/else的条件语句,但没有循环语句;
- 支持include,加载配置文件,例如
include "foo.vcl";
- 支持import,加载模块,例如
-
import std; sub vcl_recv { std.log("foo"); }
probe healthcheck { .url = "/test.jpg"; # 定义健康检查的页面 .interval = 6s; # 探测请求的发送周期,默认为5s .timeout = 0.3 s; # 每次探测请求的过期时长,默认为2s .window = 8; # 设定在判定后端主机健康状态时基于最近多少次的探测进行,默认为8 .threshold = 3; # 在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行,默认为3 .initial = 3; # Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold }
backend default { .host = "127.0.0.1"; .port = "80";
.probe = healthcheck;
.host_header = "www.example.com"; .connect_timeout = 60s; .first_byte_timeout = 60s; .between_bytes_timeout = 60s; .max_connections = 800; }
其中,host选项是必须显式赋值的,其它选项都可选;
如果host是动态域名(而非IP),Varnish会报错:resolves to too many addresses,解决办法可以参考这里。
- random,根据设置的权值(.weight参数)来选择backend;
- round-robin,轮询;
- client,根据client.identity来选择backend,可以设置client.identity的值为session cookie来标识backend;
- hash,
- dns,
import directors;
sub vcl_init {
new vdir = directors.round_robin();
vdir.add_backend(backend1);
vdir.add_backend(backend2);
}
sub vcl_recv {
set req.backend_hint = vdir.backend();
}
acl localnetwork { "localhost"; # myself "192.0.2.0"/24; # and everyone on the local network ! "192.0.2.23"; # except for the dial-in router }
if (client.ip ~ localnetwork) { return (pipe); }
- vcl_recv,用于接收和处理请求,当请求到达并成功接收后被调用,vcl_recv中的数据结构主要是req。
- vcl_fetch,获取backend响应后调用该方法,通过判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端,vcl_fetch的主要数据结构是beresp;该函数在4.0版本已分解为下面两个函数:
- vcl_backend_fetch,向后端主机发送请求前,调用此函数,可修改发往后端的请求;
- vcl_backend_response ,获得后端主机的响应后,可调用此函数;
- vcl_pipe,将请求直接传递至backend;
- vcl_pass,将请求直接传递至backend,并将backend的响应发送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容;
- vcl_hash,设置文件索引的key;
- vcl_deliver,将在缓存中找到的请求的内容发送给客户端前调用此方法;
- vcl_hit,执行lookup指令后,在缓存中找到请求的内容将自动调用该函数;
- vcl_miss,执行lookup指令后,在缓存中没有找到请求的内容将自动调用该函数,此函数可用于判断是否需要从backend获取内容;
- vcl_error,出现错误时调用此函数;
VCL 动作(Actions)
- pass,把请求控制权交给vcl_pass函数;
- lookup,在缓存中查找被请求的对象,并根据查找的结果把控制权交给函数vcl_hit或vcl_miss;
- pipe,把请求控制权交给vcl_pipe函数;
- deliver,将在缓存中找到的内容发送给客户端,并把控制权交给函数vcl_deliver;
- esi,ESI-process,
- error code [reason],返回code给客户端,并放弃处理该请求;
pipe与pass的区别
当 vcl_recv 函数接收到请求时,有三种情况 :
- 调用 pass 函数,从后端服务器调用数据;
- 调用 pipe 函数,建立客户端和后端服务器之间的直接连接,从后端服务器调用数据;
- 调用lookup函数,从缓存中查找应答数据并返回,如果查找不到,则调用pass函数从后端服务器调用数据。
pass和pipe都从后端服务器取数据,那么它们之间有什么不同呢?
pass是将当前请求直接转发到后端服务器,而后续的请求仍然通过varnish处理。 例如,建立了HTTP连接之后,客户端顺序请求 a.css 、b.png两个文件,“当前请求” 指的是第一个请求,即a.css,a.css被直接转发到后端服务器,不被缓存。而后续的b.png则再由varnish来做处理,varnish会判断b.png 如何处理。
而pipe模式则不一样,它会在客户端和服务器之间建立一条直接的连接,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到连接断开。
VCL公共变量
server.ip 表示服务器 IP
client.ip 表示客户端 IP
req.quest 只是请求的类型,例如 GET、HEAD 等
req.url 指定请求的地址
req.proto 表示客户端发起请求的 HTTP 协议版本
req.http.header 表示对应请求中的头,例如req.http.cookie
req.restarts 表示重启次数,默认最大值为 4
beresp.url 表示请求地址
beresp.proto 表示客户端发起请求的 HTTP 协议版本
beresp.http.header 表示对应请求中 HTTP 头部信息
beresp.ttl 表示缓存的生存周期,cache 保留时间(s)
obj.cacheable 返回的内容是否可以缓存
obj.valid 是否有效的 HTTP 请求
obj.response 返回内容的请求状态信息
obj.proto 返回内容的 HTTP 版本
obj.ttl 返回内容的生存周期,也就是缓存时间,单位秒
obj.lastuse 返回上一次请求到现在的时间间隔,单位秒
resp.proto 返回给客户端的 HTTP 协议版本
resp.http.header 返回给客户端的 HTTP 头部消息
resp.response 返回给客户端的 HTTP 头部状态