Varnish是一款高性能、开源的缓存反向代理服务器。它从客户端接受请求,并尝试从缓存中响应请求,如果无法从缓存中提供响应,Varnish 向后端服务器发起请求,获取响应,将响应存储在缓存中,然后把响应发送给客户端。如果Varnish能够从Cache中响应一个请求,所消耗的时间是微秒级别的,这个响应速度比直接从HTTP服务器响应请求的速度要快两个数量级,缓存命中率越高,网站的访问速度就越快。
主要特性缓存位置:可以使用内存也可以使用磁盘,如果要使用磁盘的话推荐SSD做RAID1;
日志存储:日志也存储在内存中,存储策略:固定大小,循环使用;
支持虚拟内存的使用;
有精确的时间管理机制,即缓存的时间属性控制;
状态引擎架构:在不同的引擎上完成对不同的缓存和代理数据进行处理,可以通过特定的配置语言设计不同的控制语句,以决定数据在不同位置以不同方式缓存;
缓存管理:以二叉堆格式管理缓存数据,做到数据的及时清理。
系统架构Varnish主要有两个进程:Management进程与Child进程(也称为Cache进程)。
Management进程:主要对子进程进行管理,实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等;Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。
Child进程:生成线程池,负责对用户请求进行处理,并通过hash查找返回用户结果。
Child进程包含多种类型的线程,常见的有:
Accept线程:接收新的连接请求并响应;
Worker线程:child进程会为每个会话启动一个worker线程,因此在高并发的场景中可能会出现数百个worker线程甚至更多;
Object Expiry线程:从缓存中清理过期内容;
Commad line线程 : 管理接口;
Storage/hashing线程:缓存存储;
Log/stats线程:日志管理线程;
Backend Communication线程:管理后端主机线程。
日志为了与系统的其它部分进行交互,Child进程使用可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可;需要注意,为了减少竞争,每个worker线程都使用了日志数据缓存。
共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。Varnish提供了多个不同的工具,如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。
算法Varnish的Director支持的挑选方法中主要有round-robin(轮询)和random(随机)两种。其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,并在某后端主机故障时不再将其视作挑选对象;random方法随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数指定其权重,同时还可以使用.retires参数来设定查找一个健康后端主机时的尝试次数。
Varnish2.1.0后,random挑选方法又多了两种变化形式client和hash。client类型的Director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机;client.identity默认为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。类似地,hash类型的Director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。
VCL工具Varnish Configuration Language(VCL),Varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,可以使用运算符包括“ =、==、!、&& ”等,支持使用正则表达式进行字符串匹配,允许用户使用set自定义变量,支持if判断语句,也有内置的函数和变量等。VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序,编译完成后management负责将其连接至varnish实例,即child进程。
后端存储Varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:
file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用,将整个缓存文件映射至内存区域(如果条件允许);
malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;
persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除),但仍处于测试阶段。