高性能缓存服务器
1.1 Varnish概述
一款高性能、开源的反向代理服务器和缓存服务器(一台varnish可以抵6台Squid)Varnish使用内存做为缓存设备(纯内存缓存服务器方案),相对于Squid(采用硬盘缓存),拥有更快的缓存速度(varnish内存管理完全交给内核,但当缓存内容超过阈值时,内核会自动将一部分缓存存入swap中,让出内存)
varnish主要运行两个进程:Management 进程和Child进程(也称为Cache进程)
Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此 Child进程
Child进程包含多种类型的线程,常见的如
? ?Acceptor线程:接收新的连接请求并响应
? ?Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多
? ?Expiry 线程:从缓存中清理过期内容;Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性
在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session 工作区
为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),当某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个 worker线程都使用了日志数据缓存
共享内存日志大小一般为 90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示
VCL(Varnish Configuration Language)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等
使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由 varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义
VCL 策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成
varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定
后端存储的类型包括:
? file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统函数调用将整个缓存文件映射至内存区域(如果条件允许);
? malloc:使用malloc()函数调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象
? persistent(experimental):与file的功能相同,但可以持久存储数据(即重启 varnish数据时不会被清除),仍处于测试期
varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以其仅适用于有着巨大缓存空间的场景
选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之file存储将有着更好的性能的表现。然而需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外为了保存数据结构等,varnish 自身也会占去不小的内存空间
为 varnishd 指定使用的缓存类型时,-s 选项可接受的参数格式如下:
? malloc[,size] 或file[,path[,size[,granularity]]] 或persistent,path,size {experimental}
file中的granularity用于设定缓存空间分配单位,默认单位是字节,所有其它的大小都会被圆整
? 基于内存进行缓存,重启后数据将消失
? 利用虚拟内存方式,I/O 性能好
? 支持设置 0~60 秒精确缓存时间
? VCL 配置管理比较灵活
? 32 位机器上缓存文件大小为最大 2GB
? 具有强大的管理功能
? 状态机设计巧妙,结构清晰
? 利用二叉堆管理缓存文件,可达到积极删除目的
优点
? Varnish稳定性高,当Squid和Varnish同时完成相同负荷工作时,Squid发生故障的几率高于Varnish,因为使用Squid要经常重启
? Varnish访问速度快,Varnish采用Visual Page Cache技术,所有缓存数据都直接从内存中读取,而Squid从硬盘中读取
? Varnish支持更多的并发连接,因为Varnish的TCP连接释放要比Squid快,因此在高并发情况下可以支持更多的TCP连接
? Varnish可以通过管理端口,使用正则表达式批量的清除部分缓存
? Squid属于单进程使用单核CPU,但Varnish通过fork形式打开多进程来处理,所以可以合理的使用所有核来处理相应的请求
缺点
? 高并发下,Varnish消耗更多的CPU、I/O和内存资源
? Varnish进程一旦挂起、崩溃或重启,缓存的数据会从内存中释放,此时所有的请求都会转发到后端服务器上,给后端服务器造成很大压力
? Varnish使用中如果单个url的请求通过HA/F5(负载均衡)每次请求到不同的Varnish服务器中,被请求的Varnish服务器都会被穿透到后端,而且同样的请求会在多台服务器上缓存,造成Varnish缓存的资源浪费,也造成性能下降
? Varnish不支持正向代理缓存
综上所述在访问量很大的情况下推荐使用varnish的内存缓存方式启动,而且后面需要跟多台squid服务器。主要为了防止前面的varnish服务、服务器被重启的情况下,前期肯定会有很多的穿透这样squid可以担当第二层CACHE,而且也弥补了varnish缓存在内存中重启都会释放的问题
资源浪费的问题可以在负载均衡上做url哈希,让单个url请求固定请求到一台varnish服务器上,可以解决该问题
? Receive状态:请求处理入口状态,根据VCL规则判断该请求应该Pass或Pipe,还是进入Lookup(本地查询)
? Lookup状态:进入此状态后,会在hash表中查找数据,若找到则进入Hit状态,否则进入Miss状态
? Fetch状态:在Fetch状态下,对请求进行后端获取、发送请求、获得数据,并进行本地存储
? Deliver状态:将获取到的数据发送给客户端,然后完成本次请求
? Pipe状态:不通过varnish,开通“管道”,直接有后端真实的web 节点回复客户端请求
1)配置varnish的内网IP vim /etc/sysconfig/network-scripts/ifcfg-eth0
2)配置varnish的桥接IP vim /etc/sysconfig/network-scripts/ifcfg-eth1
3)关闭防火墙 /etc/init.d/iptables stop&& chkconfig --level 35 iptables off
4)关闭selinux vim /etc/sysconfig/selinux
5)重启 reboot
1)安装varnish依赖开发环境 yum –y install install libtool ncurses-devel pcre-devel libxslt groff pkgconfig gcc gcc-c++ libedit-devel-2.11-4.20080712cvs.1.el6.x86_64 python-imaging-1.1.6-19.el6.x86_64 python-docutils-0.6-1.el6.noarch
1)上传varnish包并解压到/usr/src/下 tar -zxvf varnish-4.0.1.tgz -C /usr/src/
2)先运行脚本autogen.sh会自动设置libtool变量等信息 source autogen.sh
3)编译varnish ./configure --prefix=/usr/local/varnish --enable-debugging-symbols --enable-developer-warnings
选项解释:
--enable-debugging-symbols:开启调试,调试一些bug信息的标志,默认为“NO”
--enable-developer-warnings:启用提示警告,默认为“NO”
4)安装varnish make && make install
5)将varnish命令加入全局环境变量
echo“PATH=$PATH:/usr/local/varnish/bin/:/usr/local/varnish/sbin/”>>/etc/profil
6)立即生效全局变量 source /etc/profile
1)拷贝默认的varnish配置文件到varnish目录下
cp /usr/local/varnish/share/doc/varnish/example.vcl /usr/local/varnish/default.vcl
2)编辑varnish配置文件 vim /usr/local/varnish/default.vcl
释:
import directors; //加载directors模块,提供负载均衡
backend web1 { //定义后端服务器的标识名称
.host = "192.168.1.100"; //定义后端服务器的IP
.port = "80"; //定义后端服务器监听端口
.probe = { //开启健康检查
.url = "/"; //检查请求的URL(请求服务器的网页根目录)
.interval = 5s; //查询的间隔时长(每隔几秒检测一次)
.timeout = 1s; //超时时间,即等待后端1s都无响应即为故障
.window = 5; //判断健康状态时,依最近多少次的检测作为依据
.threshold = 3; //.window指定次数中,3次成功,才代表后端健康
}
}
sub vcl_init { //VCL初始化VMODs模块,定义director
new bar = directors.round_robin(); //定义调度算法,该处为加权轮询
bar.add_backend(web1); //添加标识名称为web1的加入director
bar.add_backend(web2); //添加标识名称为web2的加入director
}
sub vcl_recv {
set req.backend_hint = bar.backend(); //将所有的流量转发给dictctors
}
3)检测VCL配置是否有误,如输出一系列的内置配置,即无问题(当前无问题)
varnishd -C -f /usr/local/varnish/default.vcl
4)启动varnish并监听当前服务80端口
varnishd -f /usr/local/varnish/default.vcl -a 0.0.0.0:80
5)查看监听的varnish服务 netstat -utpln | grep varnish
6)动态输出varnish的缓存及客户端访问完整情况(访问时出现日志) varnishlog(命令)
? -f:指定varnish服务器的配置文件
? -aaddress:port:表示varnish对httpd的监听地址及端口
? -Taddress:port:设定varnish的 telnet管理地址及端口
? -baddress:port:表示后端服务器的地址及端口
? -d:表示使用debug调试模式
? -Pfile:varnish进程PID文件存放路径
? -s:varnish缓存文件位置与大小(-s file,文件路径,大小)
? -w:最小,最大线程和超时时间(例:-w 1200,5 1200 10)
1)配置IP地址 vim /etc/sysconfig/network-scripts/ifcfg-eth0
2)yum安装httpd(apache) yum -y install httpd
3)编辑测试网页 echo "This is Web1">/var/www/html/index.html
4)启动httpd服务 /etc/init.d/httpd start
5)设置httpd服务35级别开机自启 chkconfig --level 35 httpd on
6)关闭防火墙 /etc/init.d/iptables stop && chkconfig --level 35 iptables off
7)临时允许所有Selinux操作 setenforce 0
1)配置IP地址 vim /etc/sysconfig/network-scripts/ifcfg-eth0
2)yum安装httpd(apache) yum -y install httpd
3)编辑测试网页 echo "This is Web2">/var/www/html/index.html
4)启动httpd服务 /etc/init.d/httpd start
5)设置httpd服务35级别开机自启 chkconfig --level 35 httpd on
6)关闭防火墙 /etc/init.d/iptables stop && chkconfig --level 35 iptables off
7)临时允许所有Selinux操作 setenforce 0
浏览器===》打开http://192.168.1.10(Varnish服务器IP)
测试负载均衡
注:测试负载均衡时,由于采用加权轮询算法,因此有可能刷新几次都在Web1服务器上,可多刷新几次(半分钟左右)
ifdown eth0 //在Web1上输入,模拟Web1故障
注:测试高可用时,由于Varnish强大的缓存能力,Web1的页面会缓存,因此当将Web1停止时,可以还可以访问到Web1,这是等待一会,让Varnish自动清空缓存即可
原文地址:http://blog.51cto.com/13043516/2091209