Varnish是一款高性能的开源HTTP加速器及反向代理服务器。
varnish架构图:
Varnish 与一般服务器软件类似,分为 master 进程和 child 进程。Master 进程读入存储配置文件,调用合适的存储类型,然后创建 / 读入相应大小的缓存文件,接着 master 初始化管理该存储空间的结构体,然后 fork 并监控 child 进程。Child 进程在主线程的初始化的过程中,将前面打开的存储文件整个 mmap 到内存中,此时创建并初始化空闲结构体,挂到存储管理结构体,以待分配。Child 进程分配若干线程进行工作,主要包括一些管理线程和很多 worker 线程。
接着,开始真正的工作,varnish 的某个负责接收新 HTTP 连接线程开始等待用户,如果有新的 HTTP 连接过来,它总负责接收,然后唤醒某个等待中的线程,并把具体的处理过程交给它。Worker 线程读入 HTTP 请求的 URI,查找已有的 object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。
分配缓存的过程是这样的:它根据所读到 object 的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个 object 的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据 LRU 机制,把最旧的 object 释放掉。
释放缓存的过程是这样的:有一个超时线程,检测缓存中所有 object 的生存期,如果超初设定的 TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。
整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的 object 都考虑是在内存中,如果系统内存不足,系统会自动将其换到 swap 空间,而不需要 varnish 程序去控制。
配置使用varnish
CentOS7上epel源上直接安装使用:varnish-4.0.5
[[email protected] dylan]# yum install varnish epel源
[[email protected] dylan]# cd /etc/varnish/
[[email protected] varnish]# cp varnish.params{,.bak}
[[email protected] varnish]# systemctl start varnish.service
示例:
一台web服务器安装httpd作为后端服务器
[[email protected] ~]# vim /var/www/html/index.html
<h1> Backend Server 1</h1>
varnish主机上编辑:
[[email protected] varnish]# vim default.vcl
backend default {
.host = "192.168.0.150"; ###后端服务器地址
.port = "80"; ###端口
[[email protected] varnish]# systemctl reload varnish.service
举几个常用示例:
1、.测试缓存命中情况:
[[email protected] ~]# vim /etc/varnish/default.vcl
sub vcl_deliver {
# Happens when we have all the pieces we need, and are about to send the
# response to the client.
#
# You can do accounting or modifying the final object here.
if (obj.hits>0) { ###增加
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "Miss";
}
}
sub vcl_deliver {
# Happens when we have all the pieces we need, and are about to send the
# response to the client.
#
# You can do accounting or modifying the final object here.
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via" + " " + server.ip;
} else {
set resp.http.X-Cache = "Miss via" + " " + server.ip;
}
}
###使varnishadm工具来管理
[[email protected] ]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 ###varnishadm命令
vcl.load test1 default.vcl
200
VCL compiled.
varnish> vcl.use test1
200
VCL ‘test1‘ now active
2、缓存对象修剪
acl purgers { ###添加访问控制 varnish4.0
"127.0.0.0"/8;
"192.168.0.0"/16;
}
sub vcl_recv {
# Happens before we check if we have this in cache already.
#
# Typically you clean up the request here, removing cookies you don‘t need,
# rewriting the request, etc.
if (req.url ~"^/test.html$") {
return(pass);
}
if (req.method == "PURGE"){
if (!client.ip ~ purgers){ ###ip不属于定义端内的返回405错误
return(synth(405,"Purging not allow for" + client.ip));
}
return(purge);
}
}
sub vcl_purge {
return(synth(200,"Purged,")); ###修剪
}
管理端:
varnish> vcl.load test9 default.vcl ###重新配置
200
VCL compiled.
vcl.use test9 ###使用新配置
200
VCL ‘test9‘ now active
3、###设定多个后端主机
backend default {
.host = "192.168.0.150";
.port = "80";
}
backend appsrv { ###定义一个后端主机
.host = "192.168.0.113";
.port = "80";
}
sub vcl_recv {
# Happens before we check if we have this in cache already.
#
# Typically you clean up the request here, removing cookies you don‘t need,
# rewriting the request, etc.
if (req.url ~"(?i)\.php$") {
set req.backend_hint = appsrv;
} else {
set req.backend_hint = default;
}
}
vcl.load test10 default.vcl
200
VCL compiled.
vcl.load
varnish> vcl.use test10
200
VCL ‘test10‘ now active
4、设定负载均衡效果:
Directors:
import directors; ###首先import
backend websrv1 { ###定义两个后端主机
.host = "192.168.0.150";
.port = "80";
}
backend websrv2 {
.host = "192.168.0.115";
.port = "80";
}
sub vcl_init {
new websrvs = directors.round_robin();
websrvs.add_backend(websrv1);
websrvs.add_backend(websrv2);
}
sub vcl_recv {
set req.backend_hint = websrvs.backend();
}
管理端使用:
varnish> vcl.load test13 default.vcl
200
VCL compiled.
vcl.use test13
200
VCL ‘test13‘ now active
5、健康状态检测:
backend websrv1 {
.host = "192.168.0.115";
.host = "80";
.prode = {
.url = "/";
.interval = 1s;
.window = 8;
.threshold = 5;
.timeout = 2s;
}
}
.request =
"GET /HTTP/1.1"
"Host: 192.168.0.115"
"connection:Close"
.expected_response=200;
完整性示例:
vcl 4.0;
import directors;
# Default backend definition. Set this to point to your content server.
backend websrv1 {
.host = "192.168.0.150";
.port = "80";
.probe = {
.url = "/";
.interval = 2s;
.window = 5;
.threshold = 4;
}
}
backend websrv2 {
.host = "192.168.0.115";
.port = "80";
.probe = {
.url = "/";
.interval = 2s;
.window = 5;
.threshold = 4;
}
}
sub vcl_init {
new websrvs = directors.round_robin();
websrvs.add_backend(websrv1);
websrvs.add_backend(websrv2);
}
sub vcl_recv {
# if (req.url ~"(?i)\.php$") {
# set req.backend_hint = appsrv;
# } else {
set req.backend_hint = websrvs.backend();
# }
if (req.url ~"^/login") {
return(pass);
}
if (req.method == "PURGE"){
if (!client.ip ~ purgers){
return(synth(405,"Purging not allow for" + client.ip));
}
return(purge);
}
}
sub vcl_purge {
return(synth(200,"Purged,"));
}
acl purgers {
"127.0.0.0"/8;
"192.168.0.0"/16;
}
sub vcl_backend_response {
if (beresp.http.cache-control !~ "s-masage") {
if (bereq.url ~ "(?i)\.jpg$") {
set beresp.ttl = 7200s;
unset beresp.http.Set-Cookie;
}
if (bereq.url ~ "(?i)\.css$"){
set beresp.ttl = 3600s;
unset beresp.http.Set-Cookie;
}
}
}
sub vcl_deliver {
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via" + " " + server.ip;
} else {
set resp.http.X-Cache = "Miss via" + " " + server.ip;
}
# if (beresp.backend.name ~ "appsrv") {
# set resp.htttp.X-Server = "appsrv";
# }
}
varnish几个常用的命令工具:
varnishadm
varnishtop
varish log entry ranking
varnishlog
varnishlog.service
varnishncsa
varnishncsa.service
varnishstat
Varnish Cache statistics
varnish的运行时参数: 配置文件中修改全局生效
[[email protected] ~]# vim /etc/varnish/varnish.params
DAEMON_OPTS="-p thread_pools=4" ###设置线程池为4
[[email protected] ~]# systemctl restart varnish.service ###不能随便重启,否则缓存全部失效
[[email protected] varnish]# varnishstat ###查看状态
附:
变量
內键变量:
req.*:由客户端发来的http请求相关
req.http.*:请求报文各首部
bereq.*:由varnish向backend主机发出的http请求
bere.http.*
beresp.*:由backend主机发来的http响应报文
resp.*: 由varnish响应给client的http响应报文
resp.http.*:响应报文各首部
obj.*:存储在缓存空间的缓存对象属性,只读
client.*,server.*,storage.*:可用在所有的client side 的sub riutines中
自定义: set
常用的变量:
bereq:
bereq.http.HEADERS
bereq.request:请求方法
bereq.url:请求的url
bereq.proto:协议版本
bereq.backend:指明要调用的后端主机
beresp:
beresp.proto
beresp.status:响应的状态码
beresp.reason
beresp.backend.name
baresp.http.HEADERA:
beresp.ttl:后端服务器响应中的内容余下的生存时长
obj:
obj.hits:此对象从缓存中命中的次数;
obj.ttl:对象的ttl值
server:
server.ip
server.hostname
req.method:请求方法
req.url:请求的url