熟悉一些名词:
空间局部性:一个数据被访问时,其周边的数据也有可能被访问到
页面缓存:接入层和应用层中间的缓存,服务器缓存的是可缓存的页面,这层就是缓存层
缓存命中率
:hit/(hit+miss),一般高于30%命中率则是正向收益,好的设计系统可以达到80%到95%以上请求命中率:按照请求的数量来计算命中率
旁挂式缓存:客户端亲自去查询数据库,并且将数据复制给缓存服务器一份,下次先去找缓存服务器,如果没有命中则再去数据库服务器查询,此时这种工作方式的缓存叫做旁挂式缓存,这个客户端叫做胖客户端(smart client)
public cache:公共缓存,反向代理服务器的缓存功能
CND:Content Delivery Network 内容投递系统
GSLB:全网均衡调度
缓存有效性判断机制
:
“过期时间验证”缓存是否失效颗粒度太大,如果页面刚刚缓存应用服务器发生了变化,结果客户端拿到的就是过期数据;从而加入了条件式验证缓存的失效性,每次客户端请求到达缓存服务器,缓存服务器都要拿本地的数据和应用服务器的数据比较时间戳,如果时间戳发生了变化则缓存新的数据;这样虽然粒度小了,但是还是会有问题,如果应用服务器在同一秒页面数据变化了三次,而缓存服务器拿到的是第一份数据,这样还是会发生数据失效的问题;从而又引入了Etag(扩展标记)来标记唯一的页面数据。此时虽然解决了数据失效性的问题,但是每次客户端的请求都要去后端服务器做比较,对缓存和应用服务器都是不小的压力,我们不得不采取折中的解决方案就是“过期时间验证+条件式验证”,将不经常变动的页面做过期时间验证,变动频繁的采用条件式验证。
请求报文用于通知缓存服务如何使用缓存响应请求:
cache-request-directive =
"no-cache" 不能使用缓存系统中的缓存响应我,必须先去应用服务器做缓存验证
"no-store" 不能使用缓存系统中的缓存响应我,必须去应用服务器请求响应我
"max-age" "=" delta-seconds
"max-stale" [ "=" delta-seconds ]
"min-fresh" "=" delta-seconds
"no-transform"
"only-if-cached"
cache-extension
响应报文用于通知缓存服务器如何存储上级服务器响应的内容:
cache-response-directive =
"public" 所有缓存系统都可以缓存
"private" [ "=" <"> 1#field-name <"> ] 仅能够被私有缓存所缓存
"no-cache" [ "=" <"> 1#field-name <"> ],可缓存,但响应给客户端之前需要revalidation,即必须发出条件式请求进行缓存有效性验正
"no-store" ,不允许存储响应内容于缓存中
"no-transform" 不能转换格式
"must-revalidate" 必须重新验证
"proxy-revalidate"
"max-age" "=" delta-seconds 私有缓存最大缓存时长
"s-maxage" "=" delta-seconds 公共缓存最大缓存时长
cache-extension
Web Page Cache解决方案:squid和varnish,它们的关系就像Apache和Nginx
Varnish cache,是一套高性能的开源反向网站缓存服务器(reverse proxy server)、HTTP加速器 ,很多门户网站已经部署了varnish,并且性能要比squid高上许多,甚至比squid还稳定,且效率更高,资源占用更少。
特点:
优势:
劣势:
如上图所示,主要进程:Management、Cacher。
Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。
Manager管理的接口:
进程包括多个线程:
为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存。共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。
varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等
来分析共享内存日志中的信息并能够以指定的方式进行显示。
Varnish Configuration Language(VCL)是varnish配置缓存策略的工具,它是一种基于域(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。
使用VCL编写的缓存策略通常保存至.vcl文件中(默认文件:$varnish_home/default.vcl
),其需要编译成二进制的格式后才能由varnish调用,即编写的.vcl文件由VCL compiler来编译,VCL compiler调用C compiler来编译后由management来读取生效(读取是及时的),编译后management让各Child进程来应用生效(因为编译成sharedobject为各子进程各读取了一份)。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。
VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。
[VCL的工作流程]:
(1)Receive 状态,也就是请求处理的入口状态,根据 VCL 规则判断该请求应该是 Pass 或Pipe,或者进入 Lookup(本地查询)。
(2)Lookup 状态,进入此状态后,会在 hash 表中查找数据,若找到,则进入 Hit 状态,否则进入 miss 状态。
(3)Pass 状态,在此状态下,会进入后端请求,即进入 fetch 状态。
(4)Fetch 状态,在 Fetch 状态下,对请求进行后端的获取,发送请求,获得数据,并进行本地的存储。
(5)Deliver 状态, 将获取到的数据发送给客户端,然后完成本次请求。
说在前面:关于“内置函数/状态引擎”这两个名词概念:你只需记住varnish的缓存策略是基于vcl进行编写的
,因此可以叫vcl内置函数/vcl状态引擎,也可以叫做varnish内置函数/varnish状态引擎;“内置函数”与”状态引擎“大致可以理解为同一事物的不同体现,”内置函数“可以在.vcl文件中直接体现,而”状态引擎“是”内置函数“在实现缓存的处理过程的一种抽象,怎么理解就见仁见智吧。
上面提到VCL是配置varnish缓存策略的工具,因此缓存的处理流程还是围绕VCL展开。
缓存策略的进行是由vcl状态引擎来实现的,所谓的状态引擎就是当一个用户请求到达后,根据处理逻辑到达不同阶段,在每个阶段中需要做出的处理动作可以理解为这个状态。
详细流程:
varnish的状态节点
,又称为vcl状态引擎
,还有种叫法为varnish的vcl内置函数
。基于vcl配置的varnish缓存策略,(结合上节)总结其作用如下:
vcl_recv:用于接受和处理请求。当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。例如如何响应、怎么响应、使用哪个后端服务器等。
vcl_fetch:根据服务器端的响应作出缓存决策,如判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端。
vcl_pipe:对于无法理解的用户请求,将请求直接发往后端主机;
vcl_hash:自定义hash生成时的数据来源
vcl_pass:用于将请求直接传递至后端主机,后端主机在应答数据后将应答数据发送给客户端,但不进行任何缓存。
vcl_hit:从缓存中查找到缓存对象时要执行的操作;
vcl_miss:从缓存中款查找到缓存对象时要执行的操作;
vcl_deliver:将用户请求的内容响应给客户端时用;
vcl_error:在varnish端合成错误响应而时;
因此,其大致流程可分为如下:
vcl_recv-->vcl_hash-->vcl_hit-->vcl_deliver
vcl_recv-->vcl_hash-->vcl_miss-->vcl_fetch-->vcl_deliver
vcl_recv-->vcl_pass-->vcl_fetch-->vcl_deliver
vcl_recv-->vcl_pipe
(1) //, #, /*comment*/用于注释;
(2) sub $NAME 用于定义函数;
(3) 不支持循环;
(4) 有众多内置变量;
(5) 支持终止语句,没有返回值;
(6) “域”专用语言;
(7) 操作符: =, ==, ~, !, &&, ||
pipe 无法理解请求方法,管道直接送到后台
pass 不查缓存
常用语句:
if else
set name=value
unset name
req.http.HEADER:调用请求报文中http协议的指定的变量
req.request:请求方法
太多了,现学现查:
官方连接:https://varnish-cache.org/docs/6.3/reference/vcl.html#varnish-configuration-language
$varnish_home/default.vcl
:编写缓存策略的核心配置,通过官网学习最新的Varnish子进程的使用。
:配置varnish服务启动时,进程的工作特性,例如监听的地址和端口,缓存机制;(注:自”5.0“版本开始,已经没有此参数文件,且官方给出的参考是可以从命令行设置启动的运行参数。$varnish_home/varnish.params
涉及知识包括:vcl内置函数、常用变量、条件语句等,上文中已做一些基础入门。
需要深入学习请点击进阶传送门
通过varnishd命令来启动varnish服务:
varnishd -a 0.0.0.0:80 -s malloc,10g -t 2592000 -w 200,4000,300 -h classic,300000 -p thread_pools=10 -p session_linger=100 -p listen_depth=4096 -p lru_interval=3600 -p sess_workspace=9437184 -p http_resp_size=4194304 -p thread_pool_workspace=9437184 -u admin -g admin -f /path/varnish.vcl
下面分析下上面主要的几个参数:
-a 0.0.0.0:80 #设置varnish监听本机80端口的请求
-s malloc,10g #分配10G的内存用于缓存
-t 2592000 #设置缓存对象过期时间为30天
-w 200,4000,300 #设置线程池中最小线程和最大线程数及线程空闲时间
-h classic,300000 #设置hash算法classic,bucket推荐为缓存对象数的10倍默认为16383,simple_list算法不推荐生产环境使用,critbit算法是一个几乎无锁的树
-p thread_pools=10 #设置线程池大小
-p session_linger=100 #让session重用的时间,重用session可提高性能,这个值设的太大如果没有重用就浪费资源,如果太小重用率太低(大家自己权衡设置)
-p listen_depth=4096 #监听队列的深度
-p sess_workspace=9437184 #session工作内存的大小,vcl操作中需要用到这些内存
-p http_resp_size=4194304 #后端请响应允许的最大字节数,这个的内存就是从上面的sess_workspace分配的
-p thread_pool_workspace=9437184 #设置线程池内存大小,vcl中处理请求和响应将用到
-u admin #以admin用户运行varnish服务
-g admin #以admin组运行varnish服务
-f /path/varnish.vcl #指定vcl配置
#显示指定参数的当前统计数据
varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
#列出指定配置段的每个参数的意义
varnishstat -l -f MAIN -f MEMPOOL
-1:打印统计信息一次并退出,而不是持续更新的显示
-i taglist:可以同时使用多个-i选项,也可以一个选项跟上多个标签
-I <[taglist:]regex>:对指定的标签的值基于regex进行过滤
-x taglist:排除列表
-X <[taglist:]regex>:对指定的标签的值基于regex进行过滤,符合条件的予以排除
#登录管理程序
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
?
[sleepy↓]
?
原文:https://www.cnblogs.com/sunhongleibibi/p/11613188.html