varnish:
varnish是一个Web应用程序加速器也被称为高速缓存HTTP反向代理。可以在HTTP的任何服务器的前端安装它并将其配置为缓存服务器。varnish加速明显,它通常加速到300- 1000倍,当然这也取决于你的架构。varnish的主要特点,除了它的性能,还有就是它的配置语言,VCL的灵活性。
varnish架构:
图上显示了Varnish架构的框图。该图显示了数据流在varnish的主要部分之间。
主程序段是Manager进程,它包含在varnishd二进制程序中。该Manager进程的任务是将任务(包括缓存)委派给子进程。Manager过程确保每个任务总是有一个进程。
Manar的命令行界面(CLI)可通过以下方式访问:1)varnishadm,如解释中所述管理界面varnishadm部分,2)varnish代理vagent2,或 varnish管理控制台(VAC(通过vagent2)。
Varnish处理HTTP请求的过程如下:
Receive(vcl_recv)状态:也就是请求处理的入口状态,根据VCL规则判断该请求是应该进入 pass(vcl_pass)或者是 pipe(vcl_pipe)或者是lookup(缓存本地查询),还是purge(vcl_purge)。
Lookup 状态:进入该状态后,会在hash表中查找数据。若找到,则进入hit(vcl_hit)状态,否则进入miss(vcl_miss)状态。
Pass(vcl_pass)状态:在此状态下,对于请求会直接发往后端主机,进入到ackend_fetch(vcl_backend_fetch)状态。
Backend_Fetch(vcl_backend_fetch)状态:在此状态下,对请求会向后端服务器进行获取,发送请求,获得数据,并根据配置文件中对此类数据的缓存设置进行缓存或者其他操作。
Deliver(vcl_deliver)状态:将获取到的数据发送给客户端,完成本次请求。
内置函数
vcl_recv:用于接收和处理请求;当请求到达varnish,通过判断请求的数据来决定如何处理请求
vcl_pipe:用于将请求直接传递至后端主机,并将后端响应原封不动返回给客户端
vcl_pass:用于将请求直接传递给后端主机,但后端主机的响应并不缓存,而是直接返回给客户端
vcl_hit:在缓存中找到请求的内容后自动调用
vcl_miss:在缓存中没有找到请求的内容后自动调用。用于判断是否需要从后端服务器获取内容
vcl_hash:在vcl_recv调用后为请求创建一个hash值时,调用。此hash值将作为varnish中hash表的key
vcl_pruge:在收到 purge请求时,执行此函数,清空特定页面/资源的缓存。
vcl_deliver:将在缓存中找到的请求的内容发送给客户端前调用。
vcl_backend_fetch:向后端主机发送请求前,调用。可修改发往后端的请求
vcl_backend_response:获得后端主机的响应后,调用。
vcl_backend_error:当从后端主机获取资源时失败时,调用。
vcl_init:VCL加载时调用此函数,用于初始化varnish模块(类似于awk中的BEGIN)
vcl_fini:当所有请求都离开当前VCL,且当前VCL被弃用时,调用。用于清理varnish模块(类似于awk中的END)
内建变量:
req.:request,表示由客户端发来的请求报文相关;
bereq.:由varnish发往BE主机的httpd请求相关;
beresp.:由BE主机响应给varnish的响应报文相关;
resp.:由varnish响应给client相关;
obj.:存储在缓存空间中的缓存对象的属性;只读;
常用变量:
bereq., req.*:
bereq.http.HEADERS
bereq.request:请求方法;
bereq.url:请求的url;
bereq.proto:请求的协议版本;
bereq.backend:指明要调用的后端主机;
req.http.Cookie:客户端的请求报文中Cookie首部的值;
req.http.User-Agent ~ "chrome"
beresp., resp.:
beresp.http.HEADERS
beresp.status:响应的状态码;
reresp.proto:协议版本;
beresp.backend.name:BE主机的主机名;
beresp.ttl:BE主机响应的内容的余下的可缓存时长;
obj.*
obj.hits:此对象从缓存中命中的次数;
obj.ttl:对象的ttl值
server.*
server.ip varnish主机的ip
server.hostname varnish的主机hostname
client.*
lient.ip 请求客户端的 ip
varnish配置文件
1.varnish.params 配置varnish服务进程的工作特性,例如监听的地址和端口,缓存机制;
通常这个配置文件不需要太大的改动。
一般较为常见的改动为
指定监听的服务端口:
VARNISH_LISTEN_PORT=6081
VARNISH_LISTEN_PORT=80
设置存储类型以及大小;Varnish 4中默认使用malloc(即内存)作为缓存对象存储方式
VARNISH_STORAGE="malloc,256M"
VARNISH_STORAGE="malloc,1024M"
进程池配置,(视生产环境而定)
#DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
- default.vcl 配置各Child/Cache线程的缓存策略; 配置个缓存默认文件
默认里面为空,这里可根据需求添加
vcl 4.0;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
}
sub vcl_backend_response {
}
sub vcl_deliver {
}
[root@cnetos7 varnish]#varnishadm -S secret -T 127.0.0.1:6082 可查看默认的 default.vcl配置
vcl.show -v boot
自己做的配置样本:
vcl 4.0;
import directors; //加载后端负载均衡模块
probe healthchk { //后端健康检查
.url = "/.healthchk.html"; //检测后端是否有.healthchk文件,
.timeout = 2s; // 超时时长
.interval = 2s; //检测频度
.window = 8; // 基于最近的多少次检查来判断其健康状态
.threshold = 5; //最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的
}
backend appsrv1 { //后端服务器 动态1
.host = "192.168.18.99";
.port = "80";
.probe = healthchk;
}
backend appsrv2 { //后端服务器 动态2
.host = "192.168.18.100";
.port = "80";
.probe = healthchk;
}
backend websrv1 { //后端服务器 静态1
.host = "192.168.18.101";
.port = "80";
.probe = healthchk;
}
backend websrv2 { //后端服务器 静态2
.host = "192.168.18.102";
.port = "80";
.probe = healthchk;
}
acl purgers { //定义允许清理缓存的IP
"127.0.0.0"/8;
"192.168.18.131"/32;
}
acl baner { //定义允许清理同一类的缓存的IP
"127.0.0.1"/8;
}
sub vcl_init { //创建后端服务器组
new websrvs = directors.round_robin(); //静态组
websrvs.add_backend(websrv1);
websrvs.add_backend(websrv2);
new appsrvs = directors.round_robin(); //动态组
appsrvs.add_backend(appsrv1);
}
sub vcl_recv {
if (req.url ~ "(?i)\.(jpg|jpeg|png|gif|svg|txt|html|css|js)$") { // 请求路径中包含 图片,文本,js...格式的转到后端静态服务器组,否则转到动态服务器组
set req.backend_hint = websrvs.backup();
}else {
set req.backend_hint = appsrvs.backup();
}
if (req.url ~ "(?i)^/admin") { //请求路径中含admin的直接不缓存,直接连向后端服务器
return(pass);
}
if (req.method == "PURGE") { //如果请求方法是PURGE,也就是裁剪缓存
if (!client.ip ~ purgers) {
return(synth(405,"Purging not allowed for " + client.ip)); //如果客户端IP不在我们之前定义的ACL for purges中,提示如下信息
}
return(purge);
}
if (req.method == "BAN") { //BAN请求的处理
if (!client.ip ~ baner) {
return(synth(405,"baning not allowed for " + client.ip));
}
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return (synth(200,"Ban added"));
}
if (req.method == "PURGE") { // PURGE请求的处理
return(purge);
}
if (req.restarts == 0) { // #记录客户端ip
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;
}
}
}
sub vcl_purge { //定义裁剪缓存的提示信息
return (synth(200,"Purged."));
}
if ( beresp.status != 200 && beresp.status != 404 ) { // 如果相应的状态码不是200或者404,则不缓存
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
set beresp.ttl = 1h; //设置默认ttl缓存为 1小时
set beresp.grace = 30s; //意思在30s 内复制旧的请求结果给客户端
return (deliver);
}
sub vcl_deliver { // 为响应添加X-Cache首部,显示缓存是否命中
if (obj.hits > 0) {
set resp.http.X-Cache = " Hit via " + server.ip; //提示没有命中
} else {
set resp.http.X-Cache = " Miss via " + server.ip; // 提示有命中
}
}