什么是缓存,为何要缓存 css
在客户端和原始服务器端之间存在一个能够本身构建响应报文的服务器,这个服务器一般就是缓存服务器.为何要缓存服务器?在互联网上传输数据(这里指web浏览),数据传输一般有三个阶段:第一阶段:原始服务器到互联网;第二阶段:网络间的层层路由;第三阶段:网络到请求数据的客户端.为了提升用户体验,加速用户访问原始服务器,能够把热点数据放在缓存服务器上,缓存服务器一般放在离用户比较近的地方,如:cdn机房等,在同一个网域内客户端请求相同的数据能够直接从缓存服务器中取得,减小数据冗余,用户请求数据不用去原始服务器了,减小网络间的路由时间和服务器的压力.用户请求的数据有多少是能够从缓存服务器上取得的,取决于缓存的命中率;命中率一般又分为文档命中率和字节命中率(对于中等规模的web来讲,40%左右的命中率就能够了);缓存类型又分为:私有缓存和公共缓存;用户访问互联网的过程-->检查私有缓存,有就返回数据,没有就去请求二级代理,二级代理有就返回数据,没有就请求一级代理,最后请求原始服务器;若是有多个二级代理或一级代理,而且多个二级代理能够互相查找数据(需配置)还能够向一级代理(父代理)查找数据,这个方式叫作内容路由,内容路由须要经过ICP(缓存路由协议)通讯;html
缓存处理的具体步骤:nginx
接受请求-->解析请求(代理功能)-->查询缓存-->缓存内容的新鲜程度(非必须)-->构建响应报文(缓存服务器有数据)-->发送响应记录日志web
缓存内容的过时检查方式正则表达式
响应首部:文档过时机制:HTTP/1.0 Expires(过时时间:2014-05-08 19:00:00过时);HTTP/1.1 Cache-Control(max-age = 300s 300s过时)express
请求首部:条件式请求机制:根据时间戳:比较缓存服务器和原始服务器的数据时间戳是否一致(mtime:If-Modified-Since); 根据扩展标记:(If-None-Match):比较缓存服务器和原始服务器的数据扩展标记是否一致apache
结合机制:文档过时机制+条件式请求机制编程
原始服务器或缓存服务器控制缓存的首部(响应首部)vim
max-age 控制私有缓存的过时时间 如:max-age=3600后端
s-maxage 控制公共缓存,同上
no-store :控制位,表示不能缓存,只要后端服务器的报文首部有no-store首部,缓存服务器就不能缓存,这是遵循了缓存协议的控制规定
no-cache:能缓存,不能直接使用此缓存对象,意思是缓存对象在使用以前必须作新鲜度验证
must-revalidate:必须进行新鲜度验证.同上
private : 用户的私有数据
public: 用户的公开数据
vanish
varnish是一个轻量级的web的缓存服务器,他对nginx或apache作缓存,单个varnish的链接请求并发量大体在5000个左右,因此在大规模的站点中,可能仍是有squie主导.在中小企业的规模中作代理缓存时,varnish比较常见,varnish不支持使用过大的内存空间.
varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。
Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,若是在指定的时长内未获得Child进程的回应,Management将会重启此Child进程。
Child进程包含多种类型的线程,常见的如:
Acceptor线程:接收新的链接请求并响应;
Worker线程:child进程会为每一个会话启动一个worker线程,所以,在高并发的场景中可能会出现数百个worker线程甚至更多;
Expiry线程:从缓存中清理过时内容;
Varnish依赖“工做区(workspace)”以下降线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不一样的工做区,其中最关键的当属用于管理会话数据的session工做区。
如上图:
Management功能
Command line 提供命令行接口
Chile process mgmt 管理子进程
Initialisation 配置应用初始化
Child/cache
Command line 命令行接口
Storage/hashing 存储hash功能
Log/stats 日志
Accept 接受并处理用户请求
Backend communication 若是本地没有缓存请求的内容,就本身构建请求报文至原始服务器
Worker threads 负责处理用户请求
Object expiry 清楚过时缓存对象
varnish管理接口
CLI interface 命令行接口
Telnet interface telnet接口,为了安全,目前都禁用了
Web interface 基于web界面的监控
Log file 默认状况下varnish的日志是存在内存中的,想要存在磁盘中,须要本身配置
vamishlog 日志格式
vamishstat 获取当前状态信息
vamishhist 历史性信息
vamishtop 监控服务状态的
vamishncsa 日志格式
VCL complier VCL编译器
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命令完成。
用户请求数据:
若是请求的数据是缓存服务器不认识的,直接交给pipe;
若是是不可缓存的数据,直接交给pass,pass交给fetdh,由fetch构建请求报文交给后端服务器,后端服务器响应报文后,fetch看该报文是否可缓存,若是可缓存就先缓存而后返回给deliver.若是不能缓存就直接交给deliver
若是是可缓存数据,先查看hash表,若是hash表中有数据,则命中(hit),而后由deliver返回给客户端
若是是可缓存数据,先查看hash表,若是hash表中没有数据,则不命中(miss),miss交给fetch,fetch向后端服务器请求数据
从上面能够知道
缓存服务器的状态引擎有:vcl_recv,vcl_pass,vcl_hash,vcl_pipe,vcl_hit,vcl_miss,vcl_fetch,vcl_deliver,每个状态的下一步如何处理由return决定,在vcl_recv阶段,return(pipe)就交给vcl_pipe,return(lookup)就交给vcl_hit或vcl_miss
VCL的内置函数
VCL提供了几个函数来实现字符串的修改,添加bans,重启VCL状态引擎以及将控制权转回Varnish等。
regsub(str,regex,sub) : 将str中的内容,可以被regex匹配到的替换成sub,只替换第一个
regsuball(str,regex,sub):这两个用于基于正则表达式搜索指定的字符串并将其替换为指定的字符串;但regsuball()能够将str中可以被regex匹配到的字符串通通替换为sub,regsub()只替换一次;
ban(expression):
ban_url(regex):Bans全部其URL可以由regex匹配的缓存对象;
purge:从缓存中挑选出某对象以及其相关变种一并删除,这能够经过HTTP协议的PURGE方法完成;
hash_data(str):
return():当某VCL域运行结束时将控制权返回给Varnish,并指示Varnish如何进行后续的动做;其能够返回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等;但某特定域可能仅能返回某些特定的指令,而非前面列出的所有指令;
return(restart):从新运行整个VCL,即从新从vcl_recv开始进行处理;每一次重启都会增长req.restarts变量中的值,而max_restarts参数则用于限定最大重启次数。
vcl_recv子例程(状态引擎)
cl_recv是在Varnish完成对请求报文的解码为基本数据结构后第一个要执行的子例程,它一般有四个主要用途:
(1)修改客户端数据以减小缓存对象差别性;好比删除URL中的www.等字符;
(2)基于客户端数据选用缓存策略;好比仅缓存特定的URL请求、不缓存POST请求等;
(3)为某web应用程序执行URL重写规则;
(4)挑选合适的后端Web服务器;
可使用下面的终止语句,即经过return()向Varnish返回的指示操做:
pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;
pipe:不对客户端进行检查或作出任何操做,而是在客户端与后端服务器之间创建专用“管道”,并直接将数据在两者之间进行传送;此时,keep-alive链接中后续传送的数据也都将经过此管道进行直接传送,并不会出如今任何日志中;
lookup:在缓存中查找用户请求的对象,若是缓存中没有其请求的对象,后续操做极可能会将其请求的对象进行缓存;
error:由Varnish本身合成一个响应报文,通常是响应一个错误类信息、重定向类信息或负载均衡器返回的后端web服务器健康状态检查类信息;
vcl_recv也能够经过精巧的策略完成必定意义上的安全功能,以将某些特定的***扼杀于摇篮中。同时,它也能够检查出一些拼写类的错误并将其进行修正等。
Varnish默认的vcl_recv专门设计用来实现安全的缓存策略,它主要完成两种功能:
(1)仅处理能够识别的HTTP方法,而且只缓存GET和HEAD方法;
(2)不缓存任何用户特有的数据;
安全起见,通常在自定义的vcl_recv中不要使用return()终止语句,而是再由默认vcl_recv进行处理,并由其作出相应的处理决策。
vcl_fetch子例程(状态引擎)
如前面所述,相对于vcl_recv是根据客户端的请求做出缓存决策来讲,vcl_fetch则是根据服务器端的响应做出缓存决策。在任何VCL状态引擎中返回的pass操做都将由vcl_fetch进行后续处理。vcl_fetch中有许多可用的内置变量,好比最经常使用的用于定义某对象缓存时长的beresp.ttl变量。经过return()返回给varnish的操做指示有:
(1)deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver);
(2)hit_for_pass:不缓存此对象,但能够致使后续对此对象的请求直接送达到vcl_pass进行处理;
(3)restart:重启整个VCL,并增长重启计数;超出max_restarts限定的最大重启次数后将会返回错误信息;
(4)error code [reason]:返回指定的错误代码给客户端并丢弃此请求;
默认的vcl_fetch放弃了缓存任何使用了Set-Cookie首部的响应。
varnish的后端存储
varnish支持多种不一样类型的后端存储,这能够在varnishd启动时使用-s选项指定。后端存储的类型包括:
(1)file:使用特定的文件存储所有的缓存数据,并经过操做系统的mmap()系统调用将整个缓存文件映射至内存区域(若是条件容许);
(2)mal loc:使用malloc()库调用在varnish启动时向操做系统申请指定大小的内存空间以存储缓存对象;
(3)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用于设定缓存空间分配单位,默认单位是字节,全部其它的大小都会被圆整。
注:为了增大缓存命中率,要把请求中没必要要cookie的都移除,响应中没必要要setcookie都移除要移,除用户请求中的cookie,要在vcl_recv中进行,要移除set_cookie,要在vcl_fetch中进行
1.安装varnish
rpm -ivh varnish-3.0.4-1.el6.x86_64.rpm varnish-docs-3.0.4-1.el6.x86_64.rpm varnish-libs-3.0.4-1.el6.x86_64.rpm
rpm -ql varnish
规划:varnish服务器
公网IP:192.168.1.107
内网IP:172.16.21.1
后端web服务器,web1:172.16.21.2
后端web服务器,web2:172.16.21.3
2.配置varnish
vim /etc/sysconfig/varnish
VARNISH_LISTEN_PORT=80
VARNISH_STORAGE="malloc,100M"
注:修改配置文件后都要从新加载配置文件
vanishadmin -S /etc/varnish/secreet -T 172.0.0.1:6082
varnish>vcl.reload test1 default.vcl
3.定义后端服务器
vim /etc/varnish/default.vcl
backend default {
.host = "172.16.21.3";
.port = "80";
}
4.启动varnish,访问192.168.1.107
service varnish start
5.使用varnish的客户端管理工具
vanishadmin -S /etc/varnish/secreet -T 172.0.0.1:6082
varnish>help
200
help [command]
ping [timestamp]
auth response
quit
banner
status
start
stop
vcl.load <configname> <filename>
vcl.inline <configname> <quoted_VCLstring>
vcl.use <configname>
vcl.discard <configname>
vcl.list
vcl.show <configname>
param.show [-l] [<param>]
param.set <param> <value>
panic.show
panic.clear
storage.list
backend.list
backend.set_health matcher state
ban.url <regexp>
ban <field> <operator> <arg> [&& <field> <oper> <arg>]...
ban.list
6.查看缓存是否命中,而且从哪里命中
sub vcl_deliver {
if (obj.hits > 0){
set resp.http.X-Cache = "HIT" + server.ip; resp表示响应,http首部,名称X-Cache
} else {
set resp.http.X-Cache = "MISS";
}
}
7.对指定网页不作缓存,如test.html
sub vcl_recv {
if (req.url ~ "test.html"){
return(pass);
}
}
8.自定义缓存时长
sub vcl_fetch {
if (req.url ~ "\.(jpg|png|gif|jpeg)$") {
set beresp.ttl = 7200s;
}
if (req.url ~ "\.(html|css|js)$") {
set beresp.ttl = 1200s;
}
}
9.清除缓存
acl purger {
"127.0.0.1";
"192.168.0.0"/16;
}
sub vcl_recv {
if (req.request == "QC") {
if (!client.ip ~ purger) {
error 405 "error";
}
return(lookup);
}
}
sub vcl_hit {
if (req.request == "QC"){
purge;
error 200 "sesscee";
}
}
sub vcl_miss {
if (req.request == "QC"){
error 404 "error miss";
}
}
sub vcl_pass {
if (req.request == "QC"){
error 502 "502";
}
10.后端主机健康状态检测
backend web2{
.host = "www.a.com";
.probe = {
.url = "/.test.html"; 没有指定具体的内容表示请求到此网页就表明后端服务器正常
.interval = 1s;
.window = 5; 一共测试5次
.threshold = 2; 5次中有两次错误就认为是失败的
}
}
11.多台后端主机
backend web1 {
.host = "backweb1.magedu.com";
.port = "80";
}
director webservers random { random:调度方法,加权随机
.retries = 5; 重试次数,每一个主机健康状态检测的重试次数
{
.backend = web1; 后端real server
.weight = 2; 权重
}
{
.backend = {
.host = "backweb2.magedu.com";
.port = "80";
}
.weight = 3;
}
}
backend web1 {
.host = "172.16.21.2"
.port = "80";
}
backend web2 {
.host = "172.16.21.3";
.weight = "80";
}
director webserver random {
{
.backend = web1;
.weight = 2;
}
{
.backend = web2;
.weight = 3;
}
}
sub vcl_recv {
set req.backend = webser; 上面设置了必定要引用,不然会报错
}
12.动静分离雏形
backend web1 {
.host = "172.16.21.2";
.port = "80" ;
}
backend web2 {
.host = "172.16.21.3";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "\.(html|css|js)$"){
set req.backend = web1;
}else{
set req.backend = web2;
}
}
13.varnishadm命令
vanishadm
varnish> storage.list
varnish> backend.list
varnish> ban.url ^/shop/.* 清理缓存,ban.url后面跟一个正则表达式,慎用,任何清理缓存的操做都要慎用
14.varnishstats命令
varnishstat --help
varnishstat: invalid option -- '-'
usage: varnishstat [-1lV] [-f field_list] [-n varnish_name] [-w delay]
-1 # Print the statistics to stdout.
-f field_list # Comma separated list of fields to display.
# If it starts with '^' it is used as an exclusion list
-l # Lists the available fields to use with the -f option
-n varnish_name # The varnishd instance to get logs from
-V # Display the version number and exit
-w delay # Wait delay seconds between updates. Default is 1 second. Can also be be used with -1, -x or -j for repeated output.
-x # Print statistics to stdout as XML.
-j # Print statistics to stdout as JSON.
14.把内存中的日志保存到磁盘中
service varnishlog start
tail /var/log/varnish/varnish.log
15.防止盗链
if (req.http.referer) {
if ( !(req.http.referer ~ "http://.*a\.com"
|| req.http.referer ~ "http://.*b\.com\.cn"
|| req.http.referer ~ "http://.*c\.cn"
|| req.http.referer ~ "http://.*google\.com"
|| req.http.referer ~ "http://.*yahoo\.cn"
|| req.http.referer ~ "http://.*google\.cn"
)) {
set req.http.host = "img.test.com";
set req.url = "/images/default.jpg";
}
}
else { lookup; }