Varnish 是一个高性能的反向代理和HTTP加速器。它可以在FressBSD 6/7、Linux 2.6和Solaris 10上使用,并能表现出其高性能。计算机的内存除了主存外,还包括了CPU内的L1、L2,甚至有L3。硬盘上也有自己的高级缓存装置,Squid Cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统得知这些情况,所以这部份的工作应该交给操作系统处理。
Varnish 基本原理图
Varnish总体流程
网络流程
内部流程
主进程fork子进程,主进程等待子进程的信号,子进程退出后,主进程重新启动子进程子进程生成若干线程。
Accept线程:接受请求,将请求挂在overflow对列上 。
Work线程:多个,从对列上摘除请求,对请求进行处理,直到完成,然后处理下一个请求。
Epoll线程: 一个请求处理称作一个sesion,在sesion周期内,处理完请求后,会交给Epoll处理,监听是否还有事件发生。
Expire线程:对于缓存的对象,根据过期时间,组织成二叉堆,该线程周期检查该堆的根,处理过期的文件。
线程之间的关系:
Accept线程
监听端口,接受连接。
接受后组织成struct ses(session结构),看是否有空闲的工作线程,如果有,将请求给它,pthread_cond_signal信号通知它没有空闲线程,如果overflow过大,则放弃该请求。否则,将其挂在overflow上,继续监听。
Work线程
从overflow队列上摘取请求(struct ses),进入状态机处理,处理结束后,通过pipe通信,将struct ses发送给epoll线程。
work线程的处理过程
请求的处理过程称为session,主要是由work线程处理的。
请求是通过进入状态转换机进行分步处理,通过Varnish Configuration Language(VCL)进行定制。
request 进入状态机后的状态变化,对于每种状态,都可以通过VCL进行配置,丰富功能。
状态的基本转换如下图所示(http请求处理状态图):
Work线程处理请求的过程是根据VCL的配置而定制的状态机,典型的处理流程如下
1. Receive,请求处理的入口状态(之前还有first等状态),根据VCL判断该请求是Pass(跳过)还是进行Lookup(本地查询)
2. Lookup,在hash表中查找数据,若找到则进入hit状态,否则进入fetch状态。
3. Pass, 选择后台,进入fetch状态
4. Fetch,对请求进行后端的获取,发送请求,获得数据,并进行本地的存储
5. Deliver,将数据发送给客户端,然后进入done
6. Done,处理结束事宜,对于一些请求需要做重新处理则可能重新进行状态转换或交给epoll。
Work线程总体工作如下:
接受到请求,按状态机处理,请求结束后,关闭连接或交给Epoll
重新取请求,若没有请求,挂入空闲队列,等待信号唤醒(pthread_cond)
唤醒它有两个途径,除了前面说的accept线程外,还有就是herdtimer线程
如果是accept唤醒的,则继续按照状态机的方式处理请求,如果是herdtimer唤醒,则自杀。
工作线程的管理
Herd线程
根据配置生成指定数目的线程(min)
动态检查线程数目,生成需要的线程
Herdtimer线程
定期检查空闲的线程,对于空闲超过指定时间的线程,通知它可以自杀
工作线程管理的目的是根据请求的数量动态的调整工作线程的数目
Epoll线程,得到传过来的struct ses,若还没有过期,将socket放入epoll的事件中,事件发生时,也会将其放入到overflow中进行。
Varnish Cache简介
Hash方式
简单hash方式
单一链表,按key大小排序,通过memcmp比较查找和添加
缺点:查询效率低
Hash classic
第一层hash backet(较大的素数)包含锁
采用CRC32方法,key可配,一般是url + host
优点:查询较快
值得参考的地方:采用查找和添加分两遍进行
Storage方式
Malloc
通过malloc获取内存
通过free释放
特点:简单
Mmap file
创建大文件,通过二分法分段映射成1G以内的大块
数据的初始化
A 初始化时,将大文件分段进行mmap,每段大小在1G以内,映射好的段分配到free block数组链表中,数组下标便是页的倍数向下取整,如果块大于数组倒数第二个元素与页的乘积,则将该块连接到数组的最后一个元素的链表中。
B 分配,遍历数组,找到满足要求的空闲块,若是前B-2个没有,则从最后一个中满足要求的大块中切出一块。如果找出的块大于需要的容量,则就对其进行拆分,然后将剩下的插入到空闲块中。
C 回收,对于释放的块,看能否和相邻的块进行合并,如果可以,则合并后再重新插入到合适位置。
与Squid相比其优越性有:
1、Varnish采用了“Visual Page Cache"技术在内存的利用上,Varnish比Squid具有优势,它避免了Squid频繁在内存、磁盘中交换文件,而且在高并发情况下Varnish处理的请求远大于Squid,系统Load会高于Squid。
2、通过Varnish管理端口,可以使用正则表达式快速、批量地清除部分缓存,这一点是Squid不能具备的。
3、Varnish基于Kernel 和Ram的处理机制上比Squid成熟很多。进程挂了或reboot后,所有Cache将内容释放。
4、Varnish使用Vcl编程模式的配置文件,灵活性比squid好。
Varnish安装
官网要求要具备以下包:
To build Varnish on a Red Hat or Centos system you need the following packages installed:
automake
autoconf
libtool
ncurses-devel
libxslt
groff
pcre-devel
Pkgconfig
创建www用户和组,以及vasrnish缓存文件存放目录
/usr/sbin/groupadd www
/usr/sbin/useradd www
mkdir -p /data/sky/vcache
chmod +w /data/sky/vcache
chown -R www:www /data/sky/vcache
创建Varnish日志目录(/var/logs/):
mkdir -p /data/sky/vcache/logs
chmod +w /data/sky/vcache/logs
chown -R www:www /data/sky/vcache/logs
编译安装varnish:
tar zxvf varnish-2.1.2.tar.gz
cd varnish-1.1.2
export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig
./autogen.sh
./configure --prefix=/data/sky/vcache
make && make install
编辑配置文件(可参考/data/sky/vcache/etc/varnish/default.vcl)
/data/sky/vcache/etc/varnish/sky.vcl(单点配置)
Varnish通过反向代理请求后端IP为192.168.238.196、192.168.238.125,端口为80的web服务器(为其中一台img服务器)
backend testserver_one {
.host = "192.168.238.196";
.port = "9180";
}
backend testserver_two {
.host = "192.168.238.125";
.port = "9080";
}
director balance round-robin {
{
.backend = testserver_one;
}
{
.backend = testserver_two;
}
}
Varnish允许localhost、127.0.0.1、192.168.20.xxx三个来源IP通过PURGE方法清除缓存
acl purge {
"localhost";
"127.0.0.1";
"192.168.20.0"/24;
}
sub vcl_recv {
if ( req.request == "PURGE" ) {
if (!client.ip ~ purge) {
error 405 "Not allowed.";
}
return (lookup);
}
Varnish对host的请求进行处理,非指定的请求则返回提示信息
if ( req.http.host ~ "192.168.238.125:9180" ) {
set req.backend = balance;
Varnish对HTTP协议中的GET请求进行缓存,对POST请求透过,让其直接访问后端Web服务器
if ( req.request != "GET" ) {
return (pipe);
}
else {
return (lookup);
}
}else
{
error 404 "Sky test Server";
return (lookup);
}
}
sub vcl_hit {
if ( req.request == "PURGE " ) {
set obj.ttl = 0s;
error 200 "Purged";
}
}
sub vcl_miss {
if ( req.request == "PURGE") {
error 404 "Not in cache";
}
}
Varnish对以jpg|gif|png结尾的URL缓存时间设置1小时,对其他的URL缓存时间设置为30天(实际环境不是这样)
sub vcl_fetch {
if ( req.request == "GET" && req.url ~ ".(jpg|gif|png)$"){
set beresp.ttl = 3600s;
}else{
set beresp.ttl = 30d;
}
}
PS:
在正常的情况下,我们需要对后端机器进行健康检测以免消耗时间在等待已出问题的后端机器
响应。
backend testserver_one {
.host = "192.168.238.196";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 1s;
.window = 5;
.threshold = 3;
}
}
具体含义如下:
url 向后端请求的url
interval 相关多少次检测一次后端机器
timeout 连接超时的时间
window
Varnish will maintain a sliding window of the results. Here the window has five checks.
threshold
How many of the .window last polls must be good for the backend to be declared healthy.
安装配置好就可以运行:
/data/sky/vcache/sbin/varnishd -n /data/sky/vcache -f /data/sky/vcache/etc/varnish/sky.vcl -a 0.0.0.0:9180 -s file,/data/sky/vcache/sky_cache.data,1G -g www -u www -w 100,200,5 -T 127.0.0.0:3500
-f 指定配置文件启动
-a 监听本机的网卡的80端口
-T 指定本机的varnish管理端口
-s file 指定varnish缓存文件的位置以及大小
-w 指处理的最小请求数、最大请求数、超时时间
-g 组名
-u 用户名
-p # 服务器参数,用来优化性能
参数有;
一些常用的参数有以下选项
user root (0)
group root (0)
default_ttl 14400 [seconds]
thread_pools 1 [pools]
thread_pool_max 12000 [threads]
thread_pool_min 4000 [threads]
thread_pool_timeout 10 [seconds]
overflow_max 100 [%]
http_workspace 8192 [bytes]
sess_timeout 5 [seconds]
pipe_timeout 60 [seconds]
send_timeout 20 [seconds]
auto_restart on [bool]
fetch_chunksize 128 [kilobytes]
sendfile_threshold unlimited [bytes]
vcl_trace off [bool]
listen_address 172.16.189.1:3128
listen_depth 1024 [connections]
srcaddr_hash 1049 [buckets]
srcaddr_ttl 720 [seconds]
backend_http11 on [bool]
client_http11 on [bool]
ping_interval 3 [seconds]
client_http11=on 支持http1.1协议,但在2.1.2版本中没有看到该参数
-P(大P) /usr/local/varnish/var/varnish.pid 指定其进程码文件的位置,实现管理。
其它的一些管理命令
varnishncsa用来将Varnish访问日志写入日志文件
/data/sky/vcache/bin/varnishncsa –n /data/sky/vcache –w /data/sky/vcache/varnish.log &
通过 Varnish 管理端口進行管理(用 –help查看可用的指令)
/data/sky/vcache/bin/varnishadm -T 127.0.0.1:3500 help
(1) 例如:清除具体URL地址:
/data/sky/vcache/bin/varnishadm -T 127.0.0.1:3500 url.purge /a/
(2) 例如:清除具体URL地址:
/data/sky/vcache/bin/varnishadm -T 127.0.0.1:3500 url.purge w*$
(3) 例如:清除所有缓存:
/data/sky/vcache/bin/varnishadm -T 127.0.0.1:3500 url.purge *$
通过varnishstat监控varnish状态
/data/sky/vcache/bin/varnishstat –n /data/sky/vcache