一、Varnish简介
Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两种:内存与硬盘。但现在计算机系统的内存除了主存外,还包括了CPU内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此Squid Cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,这就是 Varnish cache设计架构。
varnish项目是2006年发布的第一个版本0.9.距今已经八年多了,此文档之前也提过varnish还不稳定,那是2007年时候编写的,经过varnish开发团队和网友们的辛苦耕耘,现在的varnish已经很健壮。很多门户网站已经部署了varnish,并且反应都很好,甚至反应比squid还稳定,且效率更高,资源占用更少。相信在反向代理,web加速方面,varnish已经有足够能力代替squid。
二、Web缓存部分首部介绍
程序能够缓存是因为程序具有局部性,时间局部性和空间局部性。缓存一般存储为键值,key为访问路径的url经过hash计算后的结果,value为服务器内容,一般缓存存储的是热点数据,切缓存中存储的数据不会大于后端web服务器的程序数据大小。缓存的对象是有生命周期的,当缓存空间耗尽的时候会根据LRU算法(最近最少使用)或其他算法对缓存空间进行清理。缓存中一般只能缓存非客户私有数据,客户私有数据和带cookie的数据可以进行缓存,但是存在风险,所以一般不对客户私有数据进行缓存。
缓存处理的步骤:接收请求 --> 解析请求 (提取请求的URL及各种首部)--> 查询缓存 --> 新鲜度检测 --> 创建响应报文 --> 发送响应 --> 记录日志(此图不一定准确,只是为了好理解)
新鲜度检测机制:
过期日期:
HTTP/1.0 Expires(Expires:Thu, 04 Jun 2015 23:38:18 GMT)
HTTP/1.1 Cache-Control: max-age(Cache-Control:max-age=600)
条件式请求首部:
If-Modified-Since:基于请求内容的时间戳作验正;
If-None-Match:基于被请求变量的实体值ETag;ETag是一个可以与Web资源关联的记号;
有效性再验正:revalidate
如果原始内容未改变,则仅响应首部(不附带body部分),响应码304 (Not Modified)
如果原始内容发生改变,则正常响应,响应码200;
如果原始内容消失,则响应404,此时缓存中的cache object也应该被删除;
缓存控制机制(Cache-Control):
请求:
no-cache:不要给我缓存的内容,要从Web服务器现取的内容
max-age:只接受Age值小于max-age的值,并且没有过期的缓存对象
(Age:当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时候)
max-statle:可以接受过期的缓存对象,但是过期时间必须小于此值
min-fresh:接收其新鲜生命期大于当前Age和min-fresh值之和的缓存对象
响应:
public:可以用Cache内容回应任何用户
private:只能缓存内容回应先前请求该内容的那个用户
no-cache:可以缓存,但是只有在跟Web服务器验证了其有效后,才能返回客户端
no-store:不允许缓存
三、Varnish的结构和工作流程
①、Management进程
Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。
②、Child/Cache 进程
Commad line 线程 : 管理接口
Storage/hashing 线程 :完成hash并进行缓存存储
Log/stats 线程:查看记录日志并统计各种状态
Accept 线程:接收新的连接请求并响应;
Backend Communication 线程:管理后端主机线程,当缓存中没有缓存需要有此进程交由后端服务器处理
Worker 线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多;
Object Expiry 线程:从缓存中清理过期内容;
③、Varnish日志
为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存。共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。
④、VCL(Varnish Configuation Language)简介
Varnish Configuration Language (VCL)是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 的后端存储
Varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:
file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);
malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;
persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;
Varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。
一个Management可以启动多个child/cache,每个child/cache子进程内部生成多个worker threads响应用户请求。Varnish是单进程多线程模式的,每个线程处理一个用户请求,但是不是所有的线程都用于用户请求,部分线程工作于Backend Communication、Log/stats等
三、Varnish的安装和配置
这里使用Centos 7通过epel源安装Varnish
[root@C7node1 /]# yum install varnish jemalloc.x86_64 0:3.6.0-1.el7 #jemalloc 一个性能非常卓越的内存分配器,由于C提供的内存分配效率过低,所以这里使用了更高性能的内存管理器 #用户malloc内存缓存对象使用 [root@C7node1 /]# rpm -ql varnish /etc/logrotate.d/varnish #日志回滚 /etc/varnish/default.vcl #varnish的配置文件 /etc/varnish/varnish.params #varnish的参数,用于配置varnish作为缓存的工作属性
配置varnish的三种应用:
①、varnishd应用程序的命令行参数(/etc/varnish/varnish.params)
Varnishd常用选项
-p param=value # set parameter。配置参数(child的进程数,worker的线程数)
-r param[,param...] # make parameter read-only。设定只读参数列表
-f file # VCL script,读取VCL配置文件
-a address:port # HTTP listen address and port。指定地址端口
-d # debug。运行于调试模式
-s [name=]kind[,options] # Backend storage specification。指定存储类型
# -s malloc[,<size>]
# -s file,<dir_or_file>,<size>,<granularity>
# -s persist{experimental}
-T address:port # Telnet listen address and port。指定管理接口
②、-p选项指明的参数:
运行时参数:也可在程序运行中,通过其CLI进行配置;
③、vcl:配置缓存系统的缓存机制;
通过vcl配置文件进行配置;先编译,后应用;依赖于c编译器;
本文出自 “马尔高” 博客,请务必保留此出处http://kgdbfmwfn.blog.51cto.com/5062471/1706060
原文地址:http://kgdbfmwfn.blog.51cto.com/5062471/1706060